summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rwxr-xr-x[-rw-r--r--]AndroidManifest.xml4
-rw-r--r--res/drawable-hdpi/btn_tp_help.pngbin0 -> 854 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_help_sel.pngbin0 -> 1343 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_sel_bg.pngbin0 -> 722 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_sel_bg_sel.pngbin0 -> 920 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_touchup.pngbin0 -> 712 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_touchup_sel.pngbin0 -> 1156 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_undo.pngbin0 -> 716 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_undo_disabled.pngbin0 -> 742 bytes
-rw-r--r--res/drawable-hdpi/btn_tp_undo_sel.pngbin0 -> 1110 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_large.pngbin0 -> 1237 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_large_sel.pngbin0 -> 890 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_med.pngbin0 -> 781 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_med_sel.pngbin0 -> 531 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_sm.pngbin0 -> 533 bytes
-rw-r--r--res/drawable-hdpi/ic_brush_size_sm_sel.pngbin0 -> 372 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_bokeh.pngbin0 -> 37030 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_fusion.pngbin0 -> 48694 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_halo.pngbin0 -> 51974 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_motion_blur.pngbin0 -> 36652 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_normal.pngbin0 -> 51977 bytes
-rw-r--r--res/drawable-hdpi/ic_tp_sketch.pngbin0 -> 49368 bytes
-rw-r--r--res/drawable-hdpi/trueportrait.pngbin0 -> 58255 bytes
-rw-r--r--res/drawable-hdpi/trueportrait_disabled.pngbin0 -> 58614 bytes
-rw-r--r--res/drawable-hdpi/trueportrait_select.pngbin0 -> 58795 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_help.pngbin0 -> 1213 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_help_sel.pngbin0 -> 1842 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_sel_bg.pngbin0 -> 941 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_sel_bg_sel.pngbin0 -> 1270 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_touchup.pngbin0 -> 952 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_touchup_sel.pngbin0 -> 1636 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_undo.pngbin0 -> 943 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_undo_disabled.pngbin0 -> 1001 bytes
-rw-r--r--res/drawable-xhdpi/btn_tp_undo_sel.pngbin0 -> 1511 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_large.pngbin0 -> 1597 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_large_sel.pngbin0 -> 1241 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_med.pngbin0 -> 795 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_med_sel.pngbin0 -> 638 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_sm.pngbin0 -> 651 bytes
-rw-r--r--res/drawable-xhdpi/ic_brush_size_sm_sel.pngbin0 -> 448 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_bokeh.pngbin0 -> 45905 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_fusion.pngbin0 -> 67647 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_halo.pngbin0 -> 75522 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_motion_blur.pngbin0 -> 46375 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_normal.pngbin0 -> 76013 bytes
-rw-r--r--res/drawable-xhdpi/ic_tp_sketch.pngbin0 -> 69590 bytes
-rw-r--r--res/drawable-xhdpi/trueportrait.pngbin0 -> 58524 bytes
-rw-r--r--res/drawable-xhdpi/trueportrait_disabled.pngbin0 -> 58866 bytes
-rw-r--r--res/drawable-xhdpi/trueportrait_select.pngbin0 -> 59073 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_help.pngbin0 -> 1880 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_help_sel.pngbin0 -> 2768 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_sel_bg.pngbin0 -> 1438 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_sel_bg_sel.pngbin0 -> 1868 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_touchup.pngbin0 -> 1501 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_touchup_sel.pngbin0 -> 2535 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_undo.pngbin0 -> 1488 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_undo_disabled.pngbin0 -> 1551 bytes
-rw-r--r--res/drawable-xxhdpi/btn_tp_undo_sel.pngbin0 -> 2241 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_large.pngbin0 -> 2435 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_large_sel.pngbin0 -> 1981 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_med.pngbin0 -> 1322 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_med_sel.pngbin0 -> 998 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_sm.pngbin0 -> 943 bytes
-rw-r--r--res/drawable-xxhdpi/ic_brush_size_sm_sel.pngbin0 -> 672 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_bokeh.pngbin0 -> 70112 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_fusion.pngbin0 -> 116296 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_halo.pngbin0 -> 139051 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_motion_blur.pngbin0 -> 69133 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_normal.pngbin0 -> 140407 bytes
-rw-r--r--res/drawable-xxhdpi/ic_tp_sketch.pngbin0 -> 120209 bytes
-rw-r--r--res/drawable-xxhdpi/trueportrait.pngbin0 -> 59078 bytes
-rw-r--r--res/drawable-xxhdpi/trueportrait_disabled.pngbin0 -> 59331 bytes
-rw-r--r--res/drawable-xxhdpi/trueportrait_select.pngbin0 -> 59595 bytes
-rw-r--r--res/drawable/tp_bg_select.xml34
-rw-r--r--res/drawable/tp_brush_large.xml34
-rw-r--r--res/drawable/tp_brush_med.xml34
-rw-r--r--res/drawable/tp_brush_sm.xml34
-rw-r--r--res/drawable/tp_help.xml34
-rw-r--r--res/drawable/tp_touch_up.xml34
-rw-r--r--res/drawable/tp_undo.xml35
-rw-r--r--res/drawable/trueportrait_background.xml35
-rw-r--r--res/layout/do_not_show_again_dialog.xml48
-rw-r--r--res/layout/filtershow_actionbar_trueportrait.xml46
-rw-r--r--res/layout/filtershow_actionbar_trueportrait_fusion.xml56
-rw-r--r--res/layout/filtershow_actionbar_trueportrait_mask.xml80
-rw-r--r--res/layout/filtershow_bottom_panel.xml10
-rw-r--r--res/layout/filtershow_export_dialog.xml141
-rw-r--r--res/layout/filtershow_seekbar.xml32
-rw-r--r--res/layout/filtershow_trueportrait_editor_panel.xml96
-rw-r--r--res/layout/filtershow_trueportrait_mask_editor.xml44
-rw-r--r--res/raw/sketch_bm.jpgbin0 -> 402989 bytes
-rwxr-xr-x[-rw-r--r--]res/values-zh-rCN/filtershow_strings.xml2
-rwxr-xr-x[-rw-r--r--]res/values-zh-rCN/strings.xml1
-rwxr-xr-x[-rw-r--r--]res/values-zh-rHK/filtershow_strings.xml1
-rwxr-xr-xres/values-zh-rHK/strings.xml1
-rwxr-xr-x[-rw-r--r--]res/values-zh-rTW/filtershow_strings.xml1
-rwxr-xr-xres/values-zh-rTW/strings.xml1
-rwxr-xr-x[-rw-r--r--]res/values/dimens.xml1
-rw-r--r--res/values/filtershow_ids.xml4
-rw-r--r--res/values/filtershow_strings.xml24
-rw-r--r--src/com/android/gallery3d/app/AbstractGalleryActivity.java3
-rw-r--r--src/com/android/gallery3d/app/AbstractPermissionActivity.java117
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/AlbumSetDataLoader.java18
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/AlbumSetPage.java1
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/GalleryActivity.java62
-rw-r--r--src/com/android/gallery3d/app/MovieActivity.java114
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/MovieControllerOverlay.java2
-rw-r--r--src/com/android/gallery3d/app/MoviePlayer.java2
-rwxr-xr-xsrc/com/android/gallery3d/app/PhotoDataAdapter.java25
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/PhotoPage.java27
-rw-r--r--src/com/android/gallery3d/app/PickerActivity.java10
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/TimeLineDataLoader.java17
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/app/TimeLinePage.java1
-rw-r--r--src/com/android/gallery3d/data/ClusterAlbum.java5
-rw-r--r--src/com/android/gallery3d/data/ClusterAlbumSet.java10
-rw-r--r--src/com/android/gallery3d/data/FilterDeleteSet.java18
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/data/FilterTypeSet.java10
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/FilterShowActivity.java291
-rw-r--r--src/com/android/gallery3d/filtershow/cache/BitmapCache.java12
-rw-r--r--src/com/android/gallery3d/filtershow/category/Action.java35
-rw-r--r--src/com/android/gallery3d/filtershow/category/CategoryAdapter.java18
-rw-r--r--src/com/android/gallery3d/filtershow/category/CategoryPanel.java9
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/category/GeometryPanel.java8
-rw-r--r--src/com/android/gallery3d/filtershow/category/MainPanel.java73
-rw-r--r--src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java87
-rw-r--r--src/com/android/gallery3d/filtershow/controller/BasicSlider.java3
-rw-r--r--src/com/android/gallery3d/filtershow/editors/Editor.java37
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorChanSat.java5
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java12
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorCrop.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorCurves.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorDraw.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java2
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorGrad.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorMakeup.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorPanel.java13
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java84
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java226
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java92
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java222
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorVignette.java5
-rw-r--r--src/com/android/gallery3d/filtershow/editors/ParametricEditor.java6
-rw-r--r--src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java77
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java6
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java39
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java1
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java158
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/ImageFilter.java33
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java11
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java11
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java12
-rwxr-xr-xsrc/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java185
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java58
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java46
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/SeeStraightActs.java12
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/filters/TrueScannerActs.java38
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java26
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java60
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java84
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java675
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/imageshow/ImageTrueScanner.java49
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/MasterImage.java39
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/Buffer.java5
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java58
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java6
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveImage.java114
-rw-r--r--src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java247
-rw-r--r--src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java57
-rw-r--r--src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java79
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/glrenderer/GLES11Canvas.java7
-rw-r--r--src/com/android/gallery3d/mpo/MpoParser.java83
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/GLRoot.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/GLRootView.java58
-rw-r--r--src/com/android/gallery3d/ui/MenuExecutor.java10
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/PhotoView.java4
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/SelectionManager.java45
-rw-r--r--src/com/android/gallery3d/ui/SelectionMenu.java6
-rwxr-xr-x[-rw-r--r--]src/com/android/gallery3d/ui/TimeLineSlotView.java4
-rw-r--r--src/com/android/gallery3d/util/GalleryUtils.java30
-rw-r--r--src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java10
-rw-r--r--src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java4
183 files changed, 4404 insertions, 618 deletions
diff --git a/Android.mk b/Android.mk
index 076efffa7..cf42b2f7c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -42,7 +42,7 @@ LOCAL_OVERRIDES_PACKAGES := Gallery Gallery3D GalleryNew3D Gallery2
LOCAL_SDK_VERSION := current
LOCAL_JNI_SHARED_LIBRARIES := libjni_gallery_eglfence libjni_gallery_filters libjni_gallery_jpegstream
-LOCAL_SHARED_LIBRARIES += libjni_dualcamera
+LOCAL_SHARED_LIBRARIES += libjni_dualcamera libjni_trueportrait
LOCAL_REQUIRED_MODULES := libts_detected_face_jni libts_face_beautify_jni
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 72a239b3d..9d5aecb39 100644..100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -341,7 +341,9 @@
android:authorities="com.android.gallery3d.photoprovider"
android:syncable="false"
android:exported="false"/>
- <activity android:name="com.android.gallery3d.gadget.WidgetClickHandler" />
+ <activity
+ android:name="com.android.gallery3d.gadget.WidgetClickHandler"
+ android:theme="@android:style/Theme.NoDisplay" />
<activity android:name="com.android.gallery3d.app.DialogPicker"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/DialogPickerTheme"/>
diff --git a/res/drawable-hdpi/btn_tp_help.png b/res/drawable-hdpi/btn_tp_help.png
new file mode 100644
index 000000000..77c9a5735
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_help.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_help_sel.png b/res/drawable-hdpi/btn_tp_help_sel.png
new file mode 100644
index 000000000..80893dd5f
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_help_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_sel_bg.png b/res/drawable-hdpi/btn_tp_sel_bg.png
new file mode 100644
index 000000000..2560ec38a
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_sel_bg.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_sel_bg_sel.png b/res/drawable-hdpi/btn_tp_sel_bg_sel.png
new file mode 100644
index 000000000..f2170e1f9
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_sel_bg_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_touchup.png b/res/drawable-hdpi/btn_tp_touchup.png
new file mode 100644
index 000000000..cd450a767
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_touchup.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_touchup_sel.png b/res/drawable-hdpi/btn_tp_touchup_sel.png
new file mode 100644
index 000000000..6b8f18c6c
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_touchup_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_undo.png b/res/drawable-hdpi/btn_tp_undo.png
new file mode 100644
index 000000000..de3edd118
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_undo.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_undo_disabled.png b/res/drawable-hdpi/btn_tp_undo_disabled.png
new file mode 100644
index 000000000..e45d76157
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_undo_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_tp_undo_sel.png b/res/drawable-hdpi/btn_tp_undo_sel.png
new file mode 100644
index 000000000..1d2e5aed1
--- /dev/null
+++ b/res/drawable-hdpi/btn_tp_undo_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_large.png b/res/drawable-hdpi/ic_brush_size_large.png
new file mode 100644
index 000000000..e67f63d0b
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_large.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_large_sel.png b/res/drawable-hdpi/ic_brush_size_large_sel.png
new file mode 100644
index 000000000..c787f8793
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_large_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_med.png b/res/drawable-hdpi/ic_brush_size_med.png
new file mode 100644
index 000000000..7dc3cd181
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_med.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_med_sel.png b/res/drawable-hdpi/ic_brush_size_med_sel.png
new file mode 100644
index 000000000..71b521856
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_med_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_sm.png b/res/drawable-hdpi/ic_brush_size_sm.png
new file mode 100644
index 000000000..afb691741
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_sm.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_brush_size_sm_sel.png b/res/drawable-hdpi/ic_brush_size_sm_sel.png
new file mode 100644
index 000000000..12601ed99
--- /dev/null
+++ b/res/drawable-hdpi/ic_brush_size_sm_sel.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_bokeh.png b/res/drawable-hdpi/ic_tp_bokeh.png
new file mode 100644
index 000000000..c63cf48cb
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_bokeh.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_fusion.png b/res/drawable-hdpi/ic_tp_fusion.png
new file mode 100644
index 000000000..8df5c0c94
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_fusion.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_halo.png b/res/drawable-hdpi/ic_tp_halo.png
new file mode 100644
index 000000000..5754b1ba5
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_halo.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_motion_blur.png b/res/drawable-hdpi/ic_tp_motion_blur.png
new file mode 100644
index 000000000..be21d3c9d
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_motion_blur.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_normal.png b/res/drawable-hdpi/ic_tp_normal.png
new file mode 100644
index 000000000..f33eb20a7
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_tp_sketch.png b/res/drawable-hdpi/ic_tp_sketch.png
new file mode 100644
index 000000000..10aa56063
--- /dev/null
+++ b/res/drawable-hdpi/ic_tp_sketch.png
Binary files differ
diff --git a/res/drawable-hdpi/trueportrait.png b/res/drawable-hdpi/trueportrait.png
new file mode 100644
index 000000000..902ffaf5f
--- /dev/null
+++ b/res/drawable-hdpi/trueportrait.png
Binary files differ
diff --git a/res/drawable-hdpi/trueportrait_disabled.png b/res/drawable-hdpi/trueportrait_disabled.png
new file mode 100644
index 000000000..8708a24d9
--- /dev/null
+++ b/res/drawable-hdpi/trueportrait_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/trueportrait_select.png b/res/drawable-hdpi/trueportrait_select.png
new file mode 100644
index 000000000..6c2e8dd4d
--- /dev/null
+++ b/res/drawable-hdpi/trueportrait_select.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_help.png b/res/drawable-xhdpi/btn_tp_help.png
new file mode 100644
index 000000000..c8bee80d7
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_help.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_help_sel.png b/res/drawable-xhdpi/btn_tp_help_sel.png
new file mode 100644
index 000000000..b5c70a6f3
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_help_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_sel_bg.png b/res/drawable-xhdpi/btn_tp_sel_bg.png
new file mode 100644
index 000000000..a905e64f2
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_sel_bg.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_sel_bg_sel.png b/res/drawable-xhdpi/btn_tp_sel_bg_sel.png
new file mode 100644
index 000000000..cdad80b15
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_sel_bg_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_touchup.png b/res/drawable-xhdpi/btn_tp_touchup.png
new file mode 100644
index 000000000..764042c9b
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_touchup.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_touchup_sel.png b/res/drawable-xhdpi/btn_tp_touchup_sel.png
new file mode 100644
index 000000000..93f9ef347
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_touchup_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_undo.png b/res/drawable-xhdpi/btn_tp_undo.png
new file mode 100644
index 000000000..6cb11713f
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_undo.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_undo_disabled.png b/res/drawable-xhdpi/btn_tp_undo_disabled.png
new file mode 100644
index 000000000..937957e29
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_undo_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_tp_undo_sel.png b/res/drawable-xhdpi/btn_tp_undo_sel.png
new file mode 100644
index 000000000..c5ef8e783
--- /dev/null
+++ b/res/drawable-xhdpi/btn_tp_undo_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_large.png b/res/drawable-xhdpi/ic_brush_size_large.png
new file mode 100644
index 000000000..4bd4db72c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_large.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_large_sel.png b/res/drawable-xhdpi/ic_brush_size_large_sel.png
new file mode 100644
index 000000000..c96e76b4b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_large_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_med.png b/res/drawable-xhdpi/ic_brush_size_med.png
new file mode 100644
index 000000000..37a0f6a2c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_med.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_med_sel.png b/res/drawable-xhdpi/ic_brush_size_med_sel.png
new file mode 100644
index 000000000..44da98afa
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_med_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_sm.png b/res/drawable-xhdpi/ic_brush_size_sm.png
new file mode 100644
index 000000000..d46aba34e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_sm.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_brush_size_sm_sel.png b/res/drawable-xhdpi/ic_brush_size_sm_sel.png
new file mode 100644
index 000000000..95fc19810
--- /dev/null
+++ b/res/drawable-xhdpi/ic_brush_size_sm_sel.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_bokeh.png b/res/drawable-xhdpi/ic_tp_bokeh.png
new file mode 100644
index 000000000..b1d9cc93f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_bokeh.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_fusion.png b/res/drawable-xhdpi/ic_tp_fusion.png
new file mode 100644
index 000000000..075eaaf56
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_fusion.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_halo.png b/res/drawable-xhdpi/ic_tp_halo.png
new file mode 100644
index 000000000..30eb7d991
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_halo.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_motion_blur.png b/res/drawable-xhdpi/ic_tp_motion_blur.png
new file mode 100644
index 000000000..ba0e1737c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_motion_blur.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_normal.png b/res/drawable-xhdpi/ic_tp_normal.png
new file mode 100644
index 000000000..de667bf3a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tp_sketch.png b/res/drawable-xhdpi/ic_tp_sketch.png
new file mode 100644
index 000000000..fa014348e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_tp_sketch.png
Binary files differ
diff --git a/res/drawable-xhdpi/trueportrait.png b/res/drawable-xhdpi/trueportrait.png
new file mode 100644
index 000000000..17f1ba425
--- /dev/null
+++ b/res/drawable-xhdpi/trueportrait.png
Binary files differ
diff --git a/res/drawable-xhdpi/trueportrait_disabled.png b/res/drawable-xhdpi/trueportrait_disabled.png
new file mode 100644
index 000000000..c0858e1f7
--- /dev/null
+++ b/res/drawable-xhdpi/trueportrait_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/trueportrait_select.png b/res/drawable-xhdpi/trueportrait_select.png
new file mode 100644
index 000000000..a334b2ad9
--- /dev/null
+++ b/res/drawable-xhdpi/trueportrait_select.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_help.png b/res/drawable-xxhdpi/btn_tp_help.png
new file mode 100644
index 000000000..95732571e
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_help.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_help_sel.png b/res/drawable-xxhdpi/btn_tp_help_sel.png
new file mode 100644
index 000000000..554774cf9
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_help_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_sel_bg.png b/res/drawable-xxhdpi/btn_tp_sel_bg.png
new file mode 100644
index 000000000..8d6eea054
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_sel_bg.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png b/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png
new file mode 100644
index 000000000..f0e53af56
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_touchup.png b/res/drawable-xxhdpi/btn_tp_touchup.png
new file mode 100644
index 000000000..4113cb796
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_touchup.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_touchup_sel.png b/res/drawable-xxhdpi/btn_tp_touchup_sel.png
new file mode 100644
index 000000000..52acfba68
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_touchup_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_undo.png b/res/drawable-xxhdpi/btn_tp_undo.png
new file mode 100644
index 000000000..448608d0b
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_undo.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_undo_disabled.png b/res/drawable-xxhdpi/btn_tp_undo_disabled.png
new file mode 100644
index 000000000..71270ae31
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_undo_disabled.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_tp_undo_sel.png b/res/drawable-xxhdpi/btn_tp_undo_sel.png
new file mode 100644
index 000000000..25a20987d
--- /dev/null
+++ b/res/drawable-xxhdpi/btn_tp_undo_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_large.png b/res/drawable-xxhdpi/ic_brush_size_large.png
new file mode 100644
index 000000000..6b91b53c8
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_large.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_large_sel.png b/res/drawable-xxhdpi/ic_brush_size_large_sel.png
new file mode 100644
index 000000000..9371f3062
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_large_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_med.png b/res/drawable-xxhdpi/ic_brush_size_med.png
new file mode 100644
index 000000000..8a7e9e1a8
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_med.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_med_sel.png b/res/drawable-xxhdpi/ic_brush_size_med_sel.png
new file mode 100644
index 000000000..d02b0c087
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_med_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_sm.png b/res/drawable-xxhdpi/ic_brush_size_sm.png
new file mode 100644
index 000000000..5757c9581
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_sm.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_brush_size_sm_sel.png b/res/drawable-xxhdpi/ic_brush_size_sm_sel.png
new file mode 100644
index 000000000..28829b209
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_brush_size_sm_sel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_bokeh.png b/res/drawable-xxhdpi/ic_tp_bokeh.png
new file mode 100644
index 000000000..598e7d42e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_bokeh.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_fusion.png b/res/drawable-xxhdpi/ic_tp_fusion.png
new file mode 100644
index 000000000..59daba460
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_fusion.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_halo.png b/res/drawable-xxhdpi/ic_tp_halo.png
new file mode 100644
index 000000000..2f608765c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_halo.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_motion_blur.png b/res/drawable-xxhdpi/ic_tp_motion_blur.png
new file mode 100644
index 000000000..2b88c9bf0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_motion_blur.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_normal.png b/res/drawable-xxhdpi/ic_tp_normal.png
new file mode 100644
index 000000000..2a153ff4c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_tp_sketch.png b/res/drawable-xxhdpi/ic_tp_sketch.png
new file mode 100644
index 000000000..cbc7d7b5a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_tp_sketch.png
Binary files differ
diff --git a/res/drawable-xxhdpi/trueportrait.png b/res/drawable-xxhdpi/trueportrait.png
new file mode 100644
index 000000000..3b46c8086
--- /dev/null
+++ b/res/drawable-xxhdpi/trueportrait.png
Binary files differ
diff --git a/res/drawable-xxhdpi/trueportrait_disabled.png b/res/drawable-xxhdpi/trueportrait_disabled.png
new file mode 100644
index 000000000..93d4926ff
--- /dev/null
+++ b/res/drawable-xxhdpi/trueportrait_disabled.png
Binary files differ
diff --git a/res/drawable-xxhdpi/trueportrait_select.png b/res/drawable-xxhdpi/trueportrait_select.png
new file mode 100644
index 000000000..d5c3b5d9d
--- /dev/null
+++ b/res/drawable-xxhdpi/trueportrait_select.png
Binary files differ
diff --git a/res/drawable/tp_bg_select.xml b/res/drawable/tp_bg_select.xml
new file mode 100644
index 000000000..bc3017740
--- /dev/null
+++ b/res/drawable/tp_bg_select.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/btn_tp_sel_bg" android:state_selected="false"></item>
+ <item android:drawable="@drawable/btn_tp_sel_bg_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_brush_large.xml b/res/drawable/tp_brush_large.xml
new file mode 100644
index 000000000..3277b933d
--- /dev/null
+++ b/res/drawable/tp_brush_large.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_brush_size_large" android:state_selected="false"></item>
+ <item android:drawable="@drawable/ic_brush_size_large_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_brush_med.xml b/res/drawable/tp_brush_med.xml
new file mode 100644
index 000000000..fceff8b9a
--- /dev/null
+++ b/res/drawable/tp_brush_med.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_brush_size_med" android:state_selected="false"></item>
+ <item android:drawable="@drawable/ic_brush_size_med_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_brush_sm.xml b/res/drawable/tp_brush_sm.xml
new file mode 100644
index 000000000..88de16828
--- /dev/null
+++ b/res/drawable/tp_brush_sm.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_brush_size_sm" android:state_selected="false"></item>
+ <item android:drawable="@drawable/ic_brush_size_sm_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_help.xml b/res/drawable/tp_help.xml
new file mode 100644
index 000000000..07a126e44
--- /dev/null
+++ b/res/drawable/tp_help.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/btn_tp_help" android:state_selected="false"></item>
+ <item android:drawable="@drawable/btn_tp_help_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_touch_up.xml b/res/drawable/tp_touch_up.xml
new file mode 100644
index 000000000..b8c1a9472
--- /dev/null
+++ b/res/drawable/tp_touch_up.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/btn_tp_touchup" android:state_selected="false"></item>
+ <item android:drawable="@drawable/btn_tp_touchup_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/tp_undo.xml b/res/drawable/tp_undo.xml
new file mode 100644
index 000000000..146d5b841
--- /dev/null
+++ b/res/drawable/tp_undo.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/btn_tp_undo_disabled" android:state_enabled="false"></item>
+ <item android:drawable="@drawable/btn_tp_undo" android:state_selected="false"></item>
+ <item android:drawable="@drawable/btn_tp_undo_sel" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/trueportrait_background.xml b/res/drawable/trueportrait_background.xml
new file mode 100644
index 000000000..b209b84f2
--- /dev/null
+++ b/res/drawable/trueportrait_background.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/trueportrait_disabled" android:state_enabled="false"></item>
+ <item android:drawable="@drawable/trueportrait" android:state_selected="false"></item>
+ <item android:drawable="@drawable/trueportrait_select" android:state_selected="true"></item>
+</selector> \ No newline at end of file
diff --git a/res/layout/do_not_show_again_dialog.xml b/res/layout/do_not_show_again_dialog.xml
new file mode 100644
index 000000000..8ddfdc191
--- /dev/null
+++ b/res/layout/do_not_show_again_dialog.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp" />
+
+ <CheckBox
+ android:id="@+id/do_not_show_chk"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:text="@string/do_not_show_again" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/filtershow_actionbar_trueportrait.xml b/res/layout/filtershow_actionbar_trueportrait.xml
new file mode 100644
index 000000000..11e81a83f
--- /dev/null
+++ b/res/layout/filtershow_actionbar_trueportrait.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" >
+
+ <ImageButton
+ android:id="@+id/editMask"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:background="@android:color/transparent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:src="@drawable/tp_touch_up" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/filtershow_actionbar_trueportrait_fusion.xml b/res/layout/filtershow_actionbar_trueportrait_fusion.xml
new file mode 100644
index 000000000..44e151b01
--- /dev/null
+++ b/res/layout/filtershow_actionbar_trueportrait_fusion.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" >
+
+ <ImageButton
+ android:id="@+id/pick_underlay"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:background="@android:color/transparent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:src="@drawable/tp_bg_select" />
+
+ <ImageButton
+ android:id="@+id/editMask"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@id/pick_underlay"
+ android:background="@android:color/transparent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:src="@drawable/tp_touch_up" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/filtershow_actionbar_trueportrait_mask.xml b/res/layout/filtershow_actionbar_trueportrait_mask.xml
new file mode 100644
index 000000000..b922dbd2d
--- /dev/null
+++ b/res/layout/filtershow_actionbar_trueportrait_mask.xml
@@ -0,0 +1,80 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" >
+
+ <ImageButton
+ android:id="@+id/maskUndo"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:background="@android:color/transparent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:src="@drawable/tp_undo" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_centerInParent="true" >
+
+ <ToggleButton
+ android:id="@+id/maskForeground"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:textOff="@string/foreground"
+ android:textOn="@string/foreground" />
+
+ <ToggleButton
+ android:id="@+id/maskBackground"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:textOff="@string/background"
+ android:textOn="@string/background" />
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/maskHelp"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:background="@android:color/transparent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:src="@drawable/tp_help" />
+
+</RelativeLayout>
diff --git a/res/layout/filtershow_bottom_panel.xml b/res/layout/filtershow_bottom_panel.xml
index 81a9d967b..f7c220833 100644
--- a/res/layout/filtershow_bottom_panel.xml
+++ b/res/layout/filtershow_bottom_panel.xml
@@ -134,5 +134,15 @@
android:padding="2dip"
android:scaleType="centerInside"
android:src="@drawable/seestraight" />
+
+ <ImageButton
+ android:id="@+id/truePortraitButton"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@android:color/transparent"
+ android:padding="2dip"
+ android:scaleType="centerInside"
+ android:src="@drawable/trueportrait_background" />
</LinearLayout>
</com.android.gallery3d.filtershow.CenteredLinearLayout> \ No newline at end of file
diff --git a/res/layout/filtershow_export_dialog.xml b/res/layout/filtershow_export_dialog.xml
index 394a89f2e..971260bdf 100644
--- a/res/layout/filtershow_export_dialog.xml
+++ b/res/layout/filtershow_export_dialog.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,93 +13,99 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="?android:attr/dialogPreferredPadding" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|center_vertical"
- android:textSize="16sp"
- android:textColor="@color/albumset_label_background"
- android:text="@string/select_output_settings"/>
-
- <GridLayout
- android:orientation="horizontal"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:alignmentMode="alignBounds"
- android:layout_marginTop="8dp"
- android:columnOrderPreserved="false"
- android:columnCount="5">
+ android:orientation="vertical"
+ android:padding="?android:attr/dialogPreferredPadding">
<TextView
- android:text="@string/size"
- android:layout_marginEnd="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|center_vertical"
+ android:text="@string/select_output_settings"
+ android:textColor="@color/albumset_label_background"
+ android:textSize="16sp" />
+
+ <GridLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:alignmentMode="alignBounds"
+ android:columnCount="5"
+ android:columnOrderPreserved="false"
+ android:orientation="horizontal">
+
+ <TextView
android:layout_gravity="start|center_vertical"
- android:textSize="16sp"
- android:textColor="@color/albumlist_label_title"/>
+ android:layout_marginEnd="8dp"
+ android:text="@string/size"
+ android:textColor="@color/albumlist_label_title"
+ android:textSize="16sp" />
- <EditText
+ <EditText
android:id="@+id/editableWidth"
+ android:layout_width="70dp"
android:layout_gravity="right|center_vertical"
android:gravity="center"
- android:layout_width="70dp"
- android:inputType="number"/>
+ android:inputType="number" />
- <TextView
- android:text="@string/x"
+ <TextView
android:layout_gravity="center"
- android:textColor="@color/albumlist_label_title"/>
+ android:text="@string/x"
+ android:textColor="@color/albumlist_label_title" />
- <EditText
+ <EditText
android:id="@+id/editableHeight"
- android:layout_gravity="left|center_vertical"
android:layout_width="70dp"
+ android:layout_gravity="left|center_vertical"
android:gravity="center"
- android:inputType="number"/>
+ android:inputType="number" />
- <TextView
+ <TextView
android:id="@+id/estimadedSize"
android:layout_gravity="end|center_vertical"
- android:textSize="16sp"
- android:textColor="@color/albumlist_label_title"/>
+ android:textColor="@color/albumlist_label_title"
+ android:textSize="16sp" />
- <LinearLayout
- android:layout_columnSpan="5"
- android:layout_marginTop="16dp"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_columnSpan="5"
+ android:layout_marginTop="16dp">
- <TextView
- android:text="@string/quality"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:textSize="16sp"
- android:textColor="@color/albumlist_label_title" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:text="@string/quality"
+ android:textColor="@color/albumlist_label_title"
+ android:textSize="16sp" />
- <SeekBar
- android:id="@+id/qualitySeekBar"
- android:layout_gravity="center"
- android:max="100"
- android:progress="100"
- android:layout_height="wrap_content"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_columnSpan="3"
- android:minWidth="250dp" />
+ <SeekBar
+ android:id="@+id/qualitySeekBar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_columnSpan="3"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:max="100"
+ android:minWidth="250dp"
+ android:progress="100" />
+
+ <TextView
+ android:id="@+id/qualityTextView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical"
+ android:textColor="@color/albumlist_label_title"
+ android:textSize="16sp" />
+ </LinearLayout>
+ </GridLayout>
+ </LinearLayout>
+
+</ScrollView>
- <TextView
- android:id="@+id/qualityTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="16sp"
- android:textColor="@color/albumlist_label_title"
- android:layout_gravity="end|center_vertical" />
- </LinearLayout>
- </GridLayout>
-</LinearLayout>
diff --git a/res/layout/filtershow_seekbar.xml b/res/layout/filtershow_seekbar.xml
index 8cb5cd979..12f8a7cbb 100644
--- a/res/layout/filtershow_seekbar.xml
+++ b/res/layout/filtershow_seekbar.xml
@@ -15,12 +15,11 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@android:style/Theme.DeviceDefault"
android:id="@+id/top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
android:visibility="visible" >
<ImageButton
@@ -28,26 +27,27 @@
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/cancel"
- android:layout_gravity="center_vertical"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
android:background="?android:attr/actionBarItemBackground" />
- <SeekBar
- android:id="@+id/primarySeekBar"
- style="@style/FilterShowSlider"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical|center_horizontal"
- android:layout_toRightOf="@+id/tvFilterName"
- android:layout_marginStart="10dp"
- android:layout_marginEnd="10dp"
- android:layout_weight="1" />
-
<ImageButton
android:id="@+id/slider_save"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/done"
- android:layout_gravity="center_vertical"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
android:background="?android:attr/actionBarItemBackground" />
-</LinearLayout>
+ <SeekBar
+ android:id="@+id/primarySeekBar"
+ style="@style/FilterShowSlider"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@id/slider_cancel"
+ android:layout_toLeftOf="@id/slider_save"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"/>
+</RelativeLayout>
diff --git a/res/layout/filtershow_trueportrait_editor_panel.xml b/res/layout/filtershow_trueportrait_editor_panel.xml
new file mode 100644
index 000000000..13b8212ac
--- /dev/null
+++ b/res/layout/filtershow_trueportrait_editor_panel.xml
@@ -0,0 +1,96 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:orientation="vertical" >
+
+ <FrameLayout
+ android:id="@+id/bottom_panel"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/category_actionbar_panel_height"
+ android:background="@color/edit_actionbar_background" >
+
+ <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:src="@drawable/cancel" />
+
+ <LinearLayout
+ android:id="@+id/brush_size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:clickable="true">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="3dp"
+ android:text="@string/brush_size"
+ android:textColor="#fff"
+ android:textSize="16sp" />
+ <ImageView
+ android:id="@+id/brush_size_sm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="3dp"
+ android:src="@drawable/tp_brush_sm" />
+ <ImageView
+ android:id="@+id/brush_size_med"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="3dp"
+ android:src="@drawable/tp_brush_med" />
+ <ImageView
+ android:id="@+id/brush_size_large"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="3dp"
+ android:src="@drawable/tp_brush_large" />
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/done"
+ android:layout_width="@dimen/category_actionbar_panel_height"
+ android:layout_height="@dimen/category_actionbar_panel_height"
+ android:layout_gravity="right"
+ android:background="@color/edit_actionbar_background"
+ android:src="@drawable/done" />
+ </FrameLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/filtershow_trueportrait_mask_editor.xml b/res/layout/filtershow_trueportrait_mask_editor.xml
new file mode 100644
index 000000000..1de55d83c
--- /dev/null
+++ b/res/layout/filtershow_trueportrait_mask_editor.xml
@@ -0,0 +1,44 @@
+<?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"
+ xmlns:iconbutton="http://schemas.android.com/apk/res/com.android.gallery3d"
+ android:id="@+id/truePortraitMaskEditor"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/category_actionbar_panel_height"
+ android:paddingTop="@dimen/category_actionbar_panel_height" >
+
+ <com.android.gallery3d.filtershow.imageshow.ImageTruePortraitMask
+ android:id="@+id/imageTruePortraitMask"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/res/raw/sketch_bm.jpg b/res/raw/sketch_bm.jpg
new file mode 100644
index 000000000..a85e96651
--- /dev/null
+++ b/res/raw/sketch_bm.jpg
Binary files differ
diff --git a/res/values-zh-rCN/filtershow_strings.xml b/res/values-zh-rCN/filtershow_strings.xml
index 0b624759c..3d73589bf 100644..100755
--- a/res/values-zh-rCN/filtershow_strings.xml
+++ b/res/values-zh-rCN/filtershow_strings.xml
@@ -157,4 +157,6 @@
<string name="color">滤镜</string>
<string name="frames">相框</string>
+
+ <string name="trueportrait_intro">此功能用于增强人像照。你可以将效果应用于照片背景,例如“模糊”和“速写”。你也可以将两张照片拼在一起来给你的人像照创建一个有趣的背景。</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 8edde3884..8e6e553ed 100644..100755
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -472,4 +472,5 @@
<string name="trim_video_exit_title">放弃更改?</string>
<string name="trim_video_exit_msg">是否放弃对当前影片的操作?</string>
<string name="trim_video_exit_discard">放弃</string>
+ <string name="do_not_show_again">不再显示</string>
</resources>
diff --git a/res/values-zh-rHK/filtershow_strings.xml b/res/values-zh-rHK/filtershow_strings.xml
index aa07bc5e0..5712e0c26 100644..100755
--- a/res/values-zh-rHK/filtershow_strings.xml
+++ b/res/values-zh-rHK/filtershow_strings.xml
@@ -153,4 +153,5 @@
<string name="filtershow_exif_f_stop" msgid="6081797865604483139">"光圈孔徑"</string>
<string name="filtershow_exif_exposure_time" msgid="4099067062781294115">"曝光時間"</string>
<string name="filtershow_exif_copyright" msgid="8801875918803737581">"版權"</string>
+ <string name="trueportrait_intro">此功能用於增強人像照。你可以將效果應用於照片背景,例如“模糊”和“速寫”。你也可以將兩張照片拼在一起來給你的人像照創建一個有趣的背景。</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 434190b43..5330be458 100755
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -437,4 +437,5 @@
<item quantity="one" msgid="6949174783125614798">"%1$d 張相片"</item>
<item quantity="other" msgid="3813306834113858135">"%1$d 張相片"</item>
</plurals>
+ <string name="do_not_show_again">不再顯示</string>
</resources>
diff --git a/res/values-zh-rTW/filtershow_strings.xml b/res/values-zh-rTW/filtershow_strings.xml
index 004f7a4bf..887f4fda1 100644..100755
--- a/res/values-zh-rTW/filtershow_strings.xml
+++ b/res/values-zh-rTW/filtershow_strings.xml
@@ -156,4 +156,5 @@
<string name="color">濾鏡</string>
<string name="frames">相框</string>
+ <string name="trueportrait_intro">此功能用於增強人像照。你可以將效果應用於照片背景,例如“模糊”和“速寫”。你也可以將兩張照片拼在一起來給你的人像照創建一個有趣的背景。</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 7d2cb2158..b5e67c14e 100755
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -454,4 +454,5 @@
<string name="action_viewtype_list">列表视图</string>
<string name="tvEmptyAlbum">O 個可用的圖片</string>
<string name="tvEmptyVideos">O 個可用的影片</string>
+ <string name="do_not_show_again">不再顯示</string>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e021d35df..65cd26152 100644..100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -171,6 +171,7 @@
<dimen name="thumbnail_margin">2dip</dimen>
<dimen name="action_item_height">175dip</dimen>
<dimen name="touch_circle_size">8dp</dimen>
+ <dimen name="crop_indicator_size">40dp</dimen>
<!-- configuration for album set page -->
<dimen name="album_set_item_image_height">120dp</dimen>
diff --git a/res/values/filtershow_ids.xml b/res/values/filtershow_ids.xml
index 0cd7082a7..8cfb25090 100644
--- a/res/values/filtershow_ids.xml
+++ b/res/values/filtershow_ids.xml
@@ -57,4 +57,8 @@
<item type="id" name="trueScannerEditor" />
<item type="id" name="hazeBusterEditor" />
<item type="id" name="seeStraightEditor" />
+ <item type="id" name="editorTruePortraitBasic" />
+ <item type="id" name="editorTruePortraitImageOnly" />
+ <item type="id" name="editorTruePortraitMask" />
+ <item type="id" name="editorTruePortraitFusion" />
</resources>
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml
index 1a4d2cde5..81b7ba535 100644
--- a/res/values/filtershow_strings.xml
+++ b/res/values/filtershow_strings.xml
@@ -208,6 +208,10 @@
<string name="sketch">Sketch</string>
<!-- Label for the "halo" dual camera effect [CHAR LIMIT=15] -->
<string name="halo">Halo</string>
+ <!-- Label for the "blur" true portrait effect [CHAR LIMIT=15] -->
+ <string name="blur">Blur</string>
+ <!-- Label for the "motion blur" true portrait effect [CHAR LIMIT=15] -->
+ <string name="motion_blur">Motion Blur</string>
<!-- Label for the Brightness effect [CHAR LIMIT=20] -->
<string name="editor_grad_brightness">Brightness</string>
<!-- Label for the Contrast filter effect [CHAR LIMIT=20] -->
@@ -348,10 +352,28 @@
<string name="fusion_pick_underlay">Pick Underlay</string>
<string name="dualcam_no_segment_toast">No segment found at this point</string>
<string name="dualcam_filter_not_supported">Dual camera filters not supported for this image</string>
+ <string name="trueportrait_intro">Allows you to enhance photos of people. You can apply effects to the background, such "blur" and "sketch". You can also merge two photos together to create interesting backgrounds for your portrait photos.</string>
+ <string name="trueportrait_no_face">True Portrait effects cannot be applied to this photo. Face not detected.</string>
+ <string name="trueportrait_edit_intro">With the Touch-Up tool, you can edit the foreground and the background. You can user your finger to paint in any areas of the foreground or background that were missed.</string>
+ <string name="trueportrait_edit_foreground_toast">Use your finger to paint in any areas of the foreground that were missed.</string>
+ <string name="trueportrait_edit_background_toast">Use your finger to paint in any areas of the background that were missed.</string>
+ <string name="trueportrait_edit_help">To zoom, use two fingers to pinch open or closed. You can also drag with two fingers to re-position the image. This can make it easier to fix any problem areas.</string>
+ <string name="trueportrait_fusion_intro">Your foreground person can be copied and pasted onto any photo in your Gallery. You can try using different background photos to create new and interesting portraits.</string>
+ <string name="do_not_show_again">Do not show again</string>
+ <string name="trueportrait_touch_up">Touch Up</string>
+ <string name="fusion_pick_background">Select Background Photo</string>
<string name="color">Color</string>
<string name="frames">Frames</string>
<string name="beautify">Beautify</string>
<string name="dualcam">Dual Camera</string>
-
+ <string name="trueportrait">True Portrait</string>
+ <string name="foreground">Foreground</string>
+ <string name="background">Background</string>
+ <string name="brush_size">Brush Size</string>
+
+ <string name="pref_trueportrait_intro_show_key" translatable="false">pref_trueportrait_intro_show_key</string>
+ <string name="pref_trueportrait_edit_intro_show_key" translatable="false">pref_trueportrait_edit_intro_show_key</string>
+ <string name="pref_trueportrait_fusion_intro_show_key" translatable="false">pref_trueportrait_fusion_intro_show_key</string>
+ <string name="pref_trueportrait_fusion_underlay_key" translatable="false">pref_trueportrait_fusion_underlay_key</string>
</resources>
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index f9b0fd6dc..709151a1a 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -51,7 +51,8 @@ import com.android.photos.data.GalleryBitmapPool;
import java.io.FileNotFoundException;
-public class AbstractGalleryActivity extends Activity implements GalleryContext {
+public abstract class AbstractGalleryActivity extends AbstractPermissionActivity
+ implements GalleryContext {
private static final String TAG = "AbstractGalleryActivity";
private GLRootView mGLRootView;
private StateManager mStateManager;
diff --git a/src/com/android/gallery3d/app/AbstractPermissionActivity.java b/src/com/android/gallery3d/app/AbstractPermissionActivity.java
new file mode 100644
index 000000000..e4fc95372
--- /dev/null
+++ b/src/com/android/gallery3d/app/AbstractPermissionActivity.java
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+package com.android.gallery3d.app;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+
+public abstract class AbstractPermissionActivity extends Activity {
+
+ public static final int PERMISSION_REQUEST_STORAGE = 1;
+ private boolean permissionGranted = false;
+
+ protected abstract void onGetPermissionsSuccess();
+ protected abstract void onGetPermissionsFailure();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestStoragePermission();
+ }
+
+ private void requestStoragePermission() {
+ String[] permissions = {
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ };
+ requestPermission(permissions, PERMISSION_REQUEST_STORAGE);
+ }
+
+ protected void requestPermission(String[] permissions, int requestCode) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ permissionGranted = true;
+ return;
+ }
+
+ boolean needRequest = false;
+ ArrayList<String> permissionList = new ArrayList<String>();
+ for (String permission : permissions) {
+ if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ permissionList.add(permission);
+ needRequest = true;
+ }
+ }
+
+ if (needRequest) {
+ int count = permissionList.size();
+ if (count > 0) {
+ String[] permissionArray = new String[count];
+ for (int i = 0; i < count; i++) {
+ permissionArray[i] = permissionList.get(i);
+ }
+
+ requestPermissions(permissionArray, requestCode);
+ }
+ }
+ permissionGranted = !needRequest;
+ }
+
+ private boolean checkPermissionGrantResults(int[] grantResults) {
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ permissionGranted = checkPermissionGrantResults(grantResults);
+ switch (requestCode) {
+ case PERMISSION_REQUEST_STORAGE: {
+ if (permissionGranted) {
+ onGetPermissionsSuccess();
+ } else {
+ onGetPermissionsFailure();
+ }
+ }
+ }
+ }
+
+ protected boolean isPermissionGranted() {
+ return permissionGranted;
+ }
+}
diff --git a/src/com/android/gallery3d/app/AlbumSetDataLoader.java b/src/com/android/gallery3d/app/AlbumSetDataLoader.java
index 909d9109c..e52b433d4 100644..100755
--- a/src/com/android/gallery3d/app/AlbumSetDataLoader.java
+++ b/src/com/android/gallery3d/app/AlbumSetDataLoader.java
@@ -28,6 +28,7 @@ import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.Path;
import com.android.gallery3d.ui.SynchronizedHandler;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -66,7 +67,7 @@ public class AlbumSetDataLoader {
private long mSourceVersion = MediaObject.INVALID_DATA_VERSION;
private int mSize;
- private DataListener mDataListener;
+ private ArrayList<DataListener> mDataListener = new ArrayList<>();
private LoadingListener mLoadingListener;
private ReloadTask mReloadTask;
@@ -224,7 +225,11 @@ public class AlbumSetDataLoader {
}
public void setModelListener(DataListener listener) {
- mDataListener = listener;
+ mDataListener.add(listener);
+ }
+
+ public void removeModelListener(DataListener listener) {
+ mDataListener.remove(listener);
}
public void setLoadingListener(LoadingListener listener) {
@@ -287,7 +292,10 @@ public class AlbumSetDataLoader {
mSourceVersion = info.version;
if (mSize != info.size) {
mSize = info.size;
- if (mDataListener != null) mDataListener.onSizeChanged(mSize);
+ if (mDataListener != null)
+ for (DataListener l : mDataListener) {
+ l.onSizeChanged(mSize);
+ }
if (mContentEnd > mSize) mContentEnd = mSize;
if (mActiveEnd > mSize) mActiveEnd = mSize;
}
@@ -303,7 +311,9 @@ public class AlbumSetDataLoader {
mTotalCount[pos] = info.totalCount;
if (mDataListener != null
&& info.index >= mActiveStart && info.index < mActiveEnd) {
- mDataListener.onContentChanged(info.index);
+ for (DataListener l : mDataListener) {
+ l.onContentChanged(info.index);
+ }
}
}
return null;
diff --git a/src/com/android/gallery3d/app/AlbumSetPage.java b/src/com/android/gallery3d/app/AlbumSetPage.java
index ec75d2aa8..580cd0961 100644..100755
--- a/src/com/android/gallery3d/app/AlbumSetPage.java
+++ b/src/com/android/gallery3d/app/AlbumSetPage.java
@@ -523,6 +523,7 @@ public class AlbumSetPage extends ActivityState implements
mSelectionManager.setSourceMediaSet(mMediaSet);
mAlbumSetDataAdapter = new AlbumSetDataLoader(
mActivity, mMediaSet, DATA_CACHE_SIZE);
+ mSelectionManager.setAlbumSetDataLoader(mAlbumSetDataAdapter);
mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener());
mAlbumSetView.setModel(mAlbumSetDataAdapter);
}
diff --git a/src/com/android/gallery3d/app/GalleryActivity.java b/src/com/android/gallery3d/app/GalleryActivity.java
index 4e5beabad..93ac5a4bc 100644..100755
--- a/src/com/android/gallery3d/app/GalleryActivity.java
+++ b/src/com/android/gallery3d/app/GalleryActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
* Not a Contribution
*
* Copyright (C) 2009 The Android Open Source Project
@@ -123,8 +123,7 @@ public final class GalleryActivity extends AbstractGalleryActivity implements On
initView();
mSavedInstanceState = savedInstanceState;
-
- if (!needRequestStoragePermission()) {
+ if (isPermissionGranted()) {
init();
}
}
@@ -144,57 +143,13 @@ public final class GalleryActivity extends AbstractGalleryActivity implements On
}
@Override
- public void onRequestPermissionsResult(int requestCode, String permissions[],
- int[] grantResults) {
- switch (requestCode) {
- case PERMISSION_REQUEST_STORAGE: {
- if (checkPermissionGrantResults(grantResults)) {
- init();
- } else {
- finish();
- }
- }
- }
- }
-
- private boolean needRequestStoragePermission() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
-
- boolean needRequest = false;
- String[] permissions = {
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_EXTERNAL_STORAGE
- };
- ArrayList<String> permissionList = new ArrayList<String>();
- for (String permission : permissions) {
- if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
- permissionList.add(permission);
- needRequest = true;
- }
- }
-
- if (needRequest) {
- int count = permissionList.size();
- if (count > 0) {
- String[] permissionArray = new String[count];
- for (int i = 0; i < count; i++) {
- permissionArray[i] = permissionList.get(i);
- }
-
- requestPermissions(permissionArray, PERMISSION_REQUEST_STORAGE);
- }
- }
-
- return needRequest;
+ protected void onGetPermissionsSuccess() {
+ init();
}
- private boolean checkPermissionGrantResults(int[] grantResults) {
- for (int result : grantResults) {
- if (result != PackageManager.PERMISSION_GRANTED) {
- return false;
- }
- }
- return true;
+ @Override
+ protected void onGetPermissionsFailure() {
+ finish();
}
private static class ActionItem {
@@ -282,8 +237,10 @@ public final class GalleryActivity extends AbstractGalleryActivity implements On
if (mDrawerLayout != null) {
if (setDrawerVisibility && mDrawerLayoutSupported) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+ mToolbar.setNavigationIcon(R.drawable.drawer);
} else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ mToolbar.setNavigationIcon(null);
}
}
}
@@ -419,6 +376,7 @@ public final class GalleryActivity extends AbstractGalleryActivity implements On
startTimelinePage();
mToolbar.setTitle(R.string.albums_title);
}
+ toggleNavDrawer(mDrawerLayoutSupported);
}
public void startAlbumPage() {
diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java
index cbea7b303..150b3807f 100644
--- a/src/com/android/gallery3d/app/MovieActivity.java
+++ b/src/com/android/gallery3d/app/MovieActivity.java
@@ -19,7 +19,6 @@ package com.android.gallery3d.app;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.ActionBar.OnMenuVisibilityListener;
-import android.app.Activity;
import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.bluetooth.BluetoothClass;
@@ -86,7 +85,7 @@ import android.bluetooth.BluetoothProfile;
* to set the action bar logo so the playback process looks more seamlessly integrated with
* the original activity.
*/
-public class MovieActivity extends Activity {
+public class MovieActivity extends AbstractPermissionActivity {
@SuppressWarnings("unused")
private static final String TAG = "MovieActivity";
private static final boolean LOG = true;
@@ -126,6 +125,7 @@ public class MovieActivity extends Activity {
private IMovieItem mMovieItem;
private IActivityHooker mMovieHooker;
private KeyguardManager mKeyguardManager;
+ private Bundle mSavedInstanceState;
private boolean mResumed = false;
private boolean mControlResumed = false;
@@ -186,14 +186,29 @@ public class MovieActivity extends Activity {
Intent intent = getIntent();
- mMovieHooker = ExtensionHelper.getHooker(this);
- initMovieInfo(intent);
-
initializeActionBar(intent);
mFinishOnCompletion = intent.getBooleanExtra(
MediaStore.EXTRA_FINISH_ON_COMPLETION, true);
mPrefs = getSharedPreferences(getApplicationContext().getPackageName(),
Context.MODE_PRIVATE);
+ mSavedInstanceState = savedInstanceState;
+ if (isPermissionGranted()) {
+ init(intent, rootView, savedInstanceState);
+ }
+
+ // DRM validation
+// Uri original = intent.getData();
+// String mimeType = intent.getType();
+// String filepath = DrmHelper.getFilePath(this, original);
+// if (DrmHelper.isDrmFile(filepath)) {
+// if (!DrmHelper.validateLicense(this, filepath, mimeType)) {
+// finish();
+// }
+// }
+ }
+
+ private void init(Intent intent, View rootView, Bundle savedInstanceState) {
+ initMovieInfo(intent);
mPlayer = new MoviePlayer(rootView, this, mMovieItem, savedInstanceState,
!mFinishOnCompletion) {
@Override
@@ -223,12 +238,7 @@ public class MovieActivity extends Activity {
// We set the background in the theme to have the launching animation.
// But for the performance (and battery), we remove the background here.
win.setBackgroundDrawable(null);
- mMovieHooker.init(this, intent);
- mMovieHooker.setParameter(null, mPlayer.getMoviePlayerExt());
- mMovieHooker.setParameter(null, mMovieItem);
- mMovieHooker.setParameter(null, mPlayer.getVideoSurface());
- mMovieHooker.onCreate(savedInstanceState);
-
+ initMovieHooker(intent, savedInstanceState);
// Determine available/supported effects
final Descriptor[] effects = AudioEffect.queryEffects();
for (final Descriptor effect : effects) {
@@ -246,16 +256,29 @@ public class MovieActivity extends Activity {
initEffects(mp.getAudioSessionId());
}
});
+ }
- // DRM validation
-// Uri original = intent.getData();
-// String mimeType = intent.getType();
-// String filepath = DrmHelper.getFilePath(this, original);
-// if (DrmHelper.isDrmFile(filepath)) {
-// if (!DrmHelper.validateLicense(this, filepath, mimeType)) {
-// finish();
-// }
-// }
+ private void initMovieHooker(Intent intent, Bundle savedInstanceState) {
+ mMovieHooker = ExtensionHelper.getHooker(this);
+ mMovieHooker.init(this, intent);
+ mMovieHooker.setParameter(null, mPlayer.getMoviePlayerExt());
+ mMovieHooker.setParameter(null, mMovieItem);
+ mMovieHooker.setParameter(null, mPlayer.getVideoSurface());
+ mMovieHooker.onCreate(savedInstanceState);
+ }
+
+
+ @Override
+ protected void onGetPermissionsSuccess() {
+ init(getIntent(), findViewById(R.id.movie_view_root), mSavedInstanceState);
+ mPlayer.requestAudioFocus();
+ mMovieHooker.onStart();
+ registerScreenReceiver();
+ }
+
+ @Override
+ protected void onGetPermissionsFailure() {
+ finish();
}
private void setActionBarLogoFromIntent(Intent intent) {
@@ -337,7 +360,6 @@ public class MovieActivity extends Activity {
// share provider is singleton, we should refresh our history file.
mShareProvider.setShareHistoryFileName(SHARE_HISTORY_FILE);
}
- refreshShareProvider(mMovieItem);
final MenuItem mi = menu.add(R.string.audio_effects);
mi.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@@ -347,14 +369,19 @@ public class MovieActivity extends Activity {
return true;
}
});
- mMovieHooker.onCreateOptionsMenu(menu);
+ if (isPermissionGranted()) {
+ refreshShareProvider(mMovieItem);
+ mMovieHooker.onCreateOptionsMenu(menu);
+ }
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- mMovieHooker.onPrepareOptionsMenu(menu);
+ if (mMovieHooker != null) {
+ mMovieHooker.onPrepareOptionsMenu(menu);
+ }
// if (mMovieItem != null
// && !DrmHelper.isShareableDrmFile(DrmHelper.getFilePath(this,
@@ -550,6 +577,10 @@ public class MovieActivity extends Activity {
@Override
public void onStart() {
+ if (!isPermissionGranted()) {
+ super.onStart();
+ return;
+ }
mPlayer.requestAudioFocus();
super.onStart();
mMovieHooker.onStart();
@@ -558,6 +589,10 @@ public class MovieActivity extends Activity {
@Override
protected void onStop() {
+ if (!isPermissionGranted()) {
+ super.onStop();
+ return;
+ }
mPlayer.abandonAudioFocus();
super.onStop();
if (mControlResumed && mPlayer != null) {
@@ -570,6 +605,10 @@ public class MovieActivity extends Activity {
@Override
public void onPause() {
+ if (!isPermissionGranted()) {
+ super.onPause();
+ return;
+ }
// Audio track will be deallocated for local video playback,
// thus recycle effect here.
releaseEffects();
@@ -588,8 +627,6 @@ public class MovieActivity extends Activity {
@Override
public void onResume() {
- invalidateOptionsMenu();
-
if ((mVirtualizerSupported) || (mBassBoostSupported)) {
final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
@@ -599,14 +636,19 @@ public class MovieActivity extends Activity {
}
mResumed = true;
- if (!isKeyguardLocked() && !mControlResumed && mPlayer != null) {
- mPlayer.onResume();
- mControlResumed = true;
- //initEffects(mPlayer.getAudioSessionId());
+ if (isPermissionGranted()) {
+ invalidateOptionsMenu();
+ if (!isKeyguardLocked() && !mControlResumed && mPlayer != null) {
+ mPlayer.onResume();
+ mControlResumed = true;
+ //initEffects(mPlayer.getAudioSessionId());
+ }
+ enhanceActionBar();
+ super.onResume();
+ mMovieHooker.onResume();
+ } else {
+ super.onResume();
}
- enhanceActionBar();
- super.onResume();
- mMovieHooker.onResume();
}
@Override
@@ -614,7 +656,9 @@ public class MovieActivity extends Activity {
super.onConfigurationChanged(newConfig);
if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ||
this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
- mPlayer.setDefaultScreenMode();
+ if(mPlayer != null) {
+ mPlayer.setDefaultScreenMode();
+ }
}
}
@@ -635,6 +679,10 @@ public class MovieActivity extends Activity {
@Override
public void onDestroy() {
+ if (!isPermissionGranted()) {
+ super.onDestroy();
+ return;
+ }
releaseEffects();
mPlayer.onDestroy();
super.onDestroy();
diff --git a/src/com/android/gallery3d/app/MovieControllerOverlay.java b/src/com/android/gallery3d/app/MovieControllerOverlay.java
index c1e36487d..9ea770c3e 100644..100755
--- a/src/com/android/gallery3d/app/MovieControllerOverlay.java
+++ b/src/com/android/gallery3d/app/MovieControllerOverlay.java
@@ -457,7 +457,7 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements
}
private class OverlayExtension implements IContrllerOverlayExt {
- private State mLastState;
+ private State mLastState = State.LOADING;
private String mPlayingInfo;
// for pause feature
private boolean mCanPause = true;
diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java
index f0d6a1ce7..162c0731c 100644
--- a/src/com/android/gallery3d/app/MoviePlayer.java
+++ b/src/com/android/gallery3d/app/MoviePlayer.java
@@ -619,7 +619,6 @@ public class MoviePlayer implements
}
if (start) {
mVideoView.start();
- mVideoView.setVisibility(View.VISIBLE);
mActivityContext.initEffects(mVideoView.getAudioSessionId());
}
//we may start video from stopVideo,
@@ -1372,6 +1371,7 @@ public class MoviePlayer implements
Log.v(TAG, "PositiveButton.onClick() mIsShowDialog="
+ mIsShowDialog);
}
+ mVideoView.setDialogShowState(false);
doStartVideo(true, mVideoPosition, mVideoLastDuration);
}
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index 05bd37687..36bde4dbd 100755
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -162,6 +162,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
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 @@ public class PhotoDataAdapter implements PhotoPage.Model {
// 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 @@ public class PhotoDataAdapter implements PhotoPage.Model {
mCameraIndex = cameraIndex;
mIsPanorama = isPanorama;
mIsStaticCamera = isStaticCamera;
+ mIsFromTimelineScreen = isFromTimelineScreen;
mThreadPool = activity.getThreadPool();
mNeedFullImage = true;
@@ -1306,11 +1308,21 @@ public class PhotoDataAdapter implements PhotoPage.Model {
}
}
mDirty = false;
+
+ if (mIsFromTimelineScreen) {
+ mSource.setClusterKind(GalleryActivity.CLUSTER_ALBUMSET_NO_TITLE);
+ }
version = mSource.reload();
//if data is not ready, continue to reload
if (version == MediaObject.INVALID_DATA_VERSION) {
continue;
}
+ if (mSource.isLoading()) {
+ mDirty = true;
+ continue;
+ } else {
+ mSourceVersion = version;
+ }
UpdateInfo info = executeAndWait(new GetUpdateInfo());
updateLoading(true);
@@ -1324,11 +1336,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
info = executeAndWait(new GetUpdateInfo());
}
- if (info.version != version) {
- info.reloadContent = true;
- info.size = mSource.getMediaItemCount();
- }
- if (!info.reloadContent) continue;
+ info.size = mSource.getMediaItemCount();
// Check it is from camera or not
boolean isCameraFlag = false;
@@ -1431,7 +1439,10 @@ public class PhotoDataAdapter implements PhotoPage.Model {
// Don't change index if mSize == 0
if (mSize > 0) {
- if (index >= mSize) index = mSize - 1;
+ // Due to the set identification and new photo, photos
+ // in the last two positions disappear in the temp info.items.
+ // Don't change index in such a situation.
+ if (index >= mSize + 2) index = mSize - 1;
}
info.indexHint = index;
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index df3229f95..3000d056b 100644..100755
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -89,7 +89,6 @@ public abstract class PhotoPage extends ActivityState implements
private static final int MSG_HIDE_BARS = 1;
private static final int MSG_ON_FULL_SCREEN_CHANGED = 4;
private static final int MSG_UPDATE_ACTION_BAR = 5;
- private static final int MSG_UNFREEZE_GLROOT = 6;
private static final int MSG_WANT_BARS = 7;
private static final int MSG_REFRESH_BOTTOM_CONTROLS = 8;
private static final int MSG_ON_CAMERA_CENTER = 9;
@@ -101,7 +100,6 @@ public abstract class PhotoPage extends ActivityState implements
private static final int MSG_UPDATE_PANORAMA_UI = 16;
private static final int HIDE_BARS_TIMEOUT = 3500;
- private static final int UNFREEZE_GLROOT_TIMEOUT = 250;
private static final int REQUEST_SLIDESHOW = 1;
private static final int REQUEST_CROP = 2;
@@ -321,10 +319,6 @@ public abstract class PhotoPage extends ActivityState implements
wantBars();
break;
}
- case MSG_UNFREEZE_GLROOT: {
- mActivity.getGLRoot().unfreeze();
- break;
- }
case MSG_UPDATE_DEFERRED: {
long nextUpdate = mDeferUpdateUntil - SystemClock.uptimeMillis();
if (nextUpdate <= 0) {
@@ -507,7 +501,8 @@ public abstract class PhotoPage extends ActivityState implements
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);
@@ -1420,7 +1415,9 @@ public abstract class PhotoPage extends ActivityState implements
mActivity.getStateManager().startState(SinglePhotoPage.class, data);
return;
}
- mModel.setCurrentPhoto(path, mCurrentIndex);
+ if (null != mModel) {
+ mModel.setCurrentPhoto(path, mCurrentIndex);
+ }
}
}
@@ -1433,7 +1430,11 @@ public abstract class PhotoPage extends ActivityState implements
mRecenterCameraOnResume = false;
switch (requestCode) {
case REQUEST_EDIT:
- setCurrentPhotoByIntent(data);
+ if (data.getData() == null) {
+ onUpPressed();
+ } else {
+ setCurrentPhotoByIntent(data);
+ }
break;
/*case REQUEST_CROP:
if (resultCode == Activity.RESULT_OK) {
@@ -1478,8 +1479,6 @@ public abstract class PhotoPage extends ActivityState implements
toolbar.setLayoutParams(layoutParams);
toolbar.setPadding(0, originalPadding, 0, 0);
}
- mActivity.getGLRoot().unfreeze();
- mHandler.removeMessages(MSG_UNFREEZE_GLROOT);
showFullScreen(false);
DetailsHelper.pause();
@@ -1514,10 +1513,6 @@ public abstract class PhotoPage extends ActivityState implements
win.setAttributes(winParams);
}
- @Override
- public void onCurrentImageUpdated() {
- mActivity.getGLRoot().unfreeze();
- }
@Override
public void onFilmModeChanged(boolean enabled) {
@@ -1604,7 +1599,6 @@ public abstract class PhotoPage extends ActivityState implements
transitionFromAlbumPageIfNeeded();
- mActivity.getGLRoot().freeze();
Toolbar toolbar = mActivity.getToolbar();
//set the new height and padding to toolbar
if (toolbar != null) {
@@ -1647,7 +1641,6 @@ public abstract class PhotoPage extends ActivityState implements
}
mRecenterCameraOnResume = true;
- mHandler.sendEmptyMessageDelayed(MSG_UNFREEZE_GLROOT, UNFREEZE_GLROOT_TIMEOUT);
if (mModel == null) {
onBackPressed();
return;
diff --git a/src/com/android/gallery3d/app/PickerActivity.java b/src/com/android/gallery3d/app/PickerActivity.java
index 09ce203ee..78d0f253e 100644
--- a/src/com/android/gallery3d/app/PickerActivity.java
+++ b/src/com/android/gallery3d/app/PickerActivity.java
@@ -80,4 +80,14 @@ public class PickerActivity extends AbstractGalleryActivity
public void onClick(View v) {
if (v.getId() == R.id.cancel) finish();
}
+
+ @Override
+ protected void onGetPermissionsSuccess() {
+
+ }
+
+ @Override
+ protected void onGetPermissionsFailure() {
+
+ }
}
diff --git a/src/com/android/gallery3d/app/TimeLineDataLoader.java b/src/com/android/gallery3d/app/TimeLineDataLoader.java
index 8fcc4dfde..590910375 100644..100755
--- a/src/com/android/gallery3d/app/TimeLineDataLoader.java
+++ b/src/com/android/gallery3d/app/TimeLineDataLoader.java
@@ -68,7 +68,7 @@ public class TimeLineDataLoader {
private final Handler mMainHandler;
private int mSize = 0;
- private DataListener mDataListener;
+ private ArrayList<DataListener> mDataListener = new ArrayList<>();
private MySourceListener mSourceListener = new MySourceListener();
private LoadingListener mLoadingListener;
@@ -240,7 +240,11 @@ public class TimeLineDataLoader {
}
public void setDataListener(DataListener listener) {
- mDataListener = listener;
+ mDataListener.add(listener);
+ }
+
+ public void removeDataListener(DataListener listener) {
+ mDataListener.remove(listener);
}
public void setLoadingListener(LoadingListener listener) {
@@ -313,7 +317,10 @@ public class TimeLineDataLoader {
mSourceVersion = info.version;
if (mSize != info.size) {
mSize = info.size;
- if (mDataListener != null) mDataListener.onSizeChanged();
+ if (mDataListener != null)
+ for (DataListener l : mDataListener) {
+ l.onSizeChanged();
+ }
if (mContentEnd > mSize) mContentEnd = mSize;
if (mActiveEnd > mSize) mActiveEnd = mSize;
}
@@ -341,7 +348,9 @@ public class TimeLineDataLoader {
mItemVersion[index] = itemVersion;
mData[index] = updateItem;
if (mDataListener != null && i >= mActiveStart && i < mActiveEnd) {
- mDataListener.onContentChanged(i);
+ for (DataListener l : mDataListener) {
+ l.onContentChanged(i);
+ }
}
}
}
diff --git a/src/com/android/gallery3d/app/TimeLinePage.java b/src/com/android/gallery3d/app/TimeLinePage.java
index 9da003eb9..978909849 100644..100755
--- a/src/com/android/gallery3d/app/TimeLinePage.java
+++ b/src/com/android/gallery3d/app/TimeLinePage.java
@@ -544,6 +544,7 @@ public class TimeLinePage extends ActivityState implements
}
mAlbumDataAdapter = new TimeLineDataLoader(mActivity, mMediaSet);
mSelectionManager.setSourceMediaSet(mMediaSet);
+ mSelectionManager.setTimeLineDataLoader(mAlbumDataAdapter);
//mSelectionManager.setAlbumDataAdapter(mAlbumDataAdapter);
mAlbumDataAdapter.setLoadingListener(new MyLoadingListener());
mAlbumView.setModel(mAlbumDataAdapter);
diff --git a/src/com/android/gallery3d/data/ClusterAlbum.java b/src/com/android/gallery3d/data/ClusterAlbum.java
index b7d1c3f36..4e2cc18ea 100644
--- a/src/com/android/gallery3d/data/ClusterAlbum.java
+++ b/src/com/android/gallery3d/data/ClusterAlbum.java
@@ -179,6 +179,11 @@ public class ClusterAlbum extends MediaSet implements ContentListener {
}
@Override
+ public boolean isLoading() {
+ return mClusterAlbumSet.isLoading();
+ }
+
+ @Override
public long reload() {
long version = mClusterAlbumSet.reload();
if (version == INVALID_DATA_VERSION) {
diff --git a/src/com/android/gallery3d/data/ClusterAlbumSet.java b/src/com/android/gallery3d/data/ClusterAlbumSet.java
index 0986a8d69..7695bd35c 100644
--- a/src/com/android/gallery3d/data/ClusterAlbumSet.java
+++ b/src/com/android/gallery3d/data/ClusterAlbumSet.java
@@ -32,6 +32,7 @@ public class ClusterAlbumSet extends MediaSet implements ContentListener {
private MediaSet mBaseSet;
private int mKind;
private ArrayList<ClusterAlbum> mAlbums = new ArrayList<ClusterAlbum>();
+ private boolean mIsLoading;
private int mTotalMediaItemCount;
/** mTotalSelectableMediaItemCount is the count of items
@@ -64,11 +65,18 @@ public class ClusterAlbumSet extends MediaSet implements ContentListener {
}
@Override
+ public synchronized boolean isLoading() {
+ return mIsLoading;
+ }
+
+ @Override
public long reload() {
synchronized (this) {
long version = mBaseSet.reload();
- if (version > mDataVersion && !mBaseSet.isLoading()) {
+ mIsLoading = mBaseSet.isLoading();
+ if (version > mDataVersion && !mIsLoading) {
updateClusters();
+ mIsLoading = false;
mDataVersion = nextVersionNumber();
}
if (mKind == ClusterSource.CLUSTER_ALBUMSET_TIME) {
diff --git a/src/com/android/gallery3d/data/FilterDeleteSet.java b/src/com/android/gallery3d/data/FilterDeleteSet.java
index fcf0dec74..799ea0e16 100644
--- a/src/com/android/gallery3d/data/FilterDeleteSet.java
+++ b/src/com/android/gallery3d/data/FilterDeleteSet.java
@@ -35,6 +35,8 @@ public class FilterDeleteSet extends MediaSet implements ContentListener {
private static final int REQUEST_REMOVE = 2;
private static final int REQUEST_CLEAR = 3;
+ private boolean mIsLoading;
+
private static class Request {
int type; // one of the REQUEST_* constants
Path path;
@@ -136,17 +138,28 @@ public class FilterDeleteSet extends MediaSet implements ContentListener {
for (int m = j - 1; m >= i; m--) {
Deletion d = mCurrent.get(m);
int k = d.index - (start + i);
- base.remove(k);
+ if (k >= 0 && k < base.size()) {
+ base.remove(k);
+ }
}
return base;
}
+ @Override
+ public boolean isLoading() {
+ return mIsLoading;
+ }
+
// We apply the pending requests in the mRequests to construct mCurrent in reload().
@Override
public long reload() {
+ mIsLoading = true;
boolean newData = mBaseSet.reload() > mDataVersion;
synchronized (mRequests) {
if (!newData && mRequests.isEmpty()) {
+ if (!mBaseSet.isLoading()) {
+ mIsLoading = false;
+ }
return mDataVersion;
}
for (int i = 0; i < mRequests.size(); i++) {
@@ -220,6 +233,9 @@ public class FilterDeleteSet extends MediaSet implements ContentListener {
}
mDataVersion = nextVersionNumber();
+ if (!mBaseSet.isLoading()) {
+ mIsLoading = false;
+ }
return mDataVersion;
}
diff --git a/src/com/android/gallery3d/data/FilterTypeSet.java b/src/com/android/gallery3d/data/FilterTypeSet.java
index e778ceb12..50a7c6964 100644..100755
--- a/src/com/android/gallery3d/data/FilterTypeSet.java
+++ b/src/com/android/gallery3d/data/FilterTypeSet.java
@@ -64,6 +64,10 @@ public class FilterTypeSet extends MediaSet implements ContentListener {
mPaths, start, count, mDataManager);
}
+ public ArrayList<Path> getPaths() {
+ return mPaths;
+ }
+
@Override
public long reload() {
if (mBaseSet.reload() > mDataVersion) {
@@ -88,12 +92,18 @@ public class FilterTypeSet extends MediaSet implements ContentListener {
String filteredPath = basePath + "/{" + set.getPath().toString() + "}";
MediaSet filteredSet = mDataManager.getMediaSet(filteredPath);
filteredSet.reload();
+ if (filteredSet instanceof FilterTypeSet && ((FilterTypeSet)filteredSet).getPaths() != null) {
+ mPaths.addAll(((FilterTypeSet)filteredSet).getPaths());
+ }
if (filteredSet.getMediaItemCount() > 0
|| filteredSet.getSubMediaSetCount() > 0) {
mAlbums.add(filteredSet);
}
}
+ if (mPaths.size() > 0) {
+ return;
+ }
// Items
mPaths.clear();
final int total = mBaseSet.getMediaItemCount();
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 0f0604ab4..452f4014c 100644..100755
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -19,8 +19,8 @@ package com.android.gallery3d.filtershow;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Vector;
import java.util.Locale;
+import java.util.Vector;
import android.app.ActionBar;
import android.app.AlertDialog;
@@ -57,15 +57,14 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewPropertyAnimator;
+import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
@@ -90,6 +89,7 @@ import com.android.gallery3d.filtershow.category.EditorCropPanel;
import com.android.gallery3d.filtershow.category.MainPanel;
import com.android.gallery3d.filtershow.category.StraightenPanel;
import com.android.gallery3d.filtershow.category.SwipableView;
+import com.android.gallery3d.filtershow.category.TruePortraitMaskEditorPanel;
import com.android.gallery3d.filtershow.category.TrueScannerPanel;
import com.android.gallery3d.filtershow.data.UserPresetsManager;
import com.android.gallery3d.filtershow.editors.Editor;
@@ -98,6 +98,9 @@ import com.android.gallery3d.filtershow.editors.EditorDualCamFusion;
import com.android.gallery3d.filtershow.editors.EditorManager;
import com.android.gallery3d.filtershow.editors.EditorPanel;
import com.android.gallery3d.filtershow.editors.EditorStraighten;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitImageOnly;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
import com.android.gallery3d.filtershow.editors.HazeBusterEditor;
import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
import com.android.gallery3d.filtershow.editors.SeeStraightEditor;
@@ -125,6 +128,7 @@ import com.android.gallery3d.filtershow.state.StateAdapter;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine.DdmStatus;
import com.android.gallery3d.filtershow.tools.SaveImage;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
import com.android.gallery3d.filtershow.tools.XmpPresets;
import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults;
import com.android.gallery3d.filtershow.ui.ExportDialog;
@@ -132,11 +136,15 @@ import com.android.gallery3d.filtershow.ui.FramedTextButton;
import com.android.gallery3d.mpo.MpoParser;
import com.android.gallery3d.util.GalleryUtils;
import com.android.photos.data.GalleryBitmapPool;
+import com.thundersoft.hz.selfportrait.detect.FaceDetect;
+import com.thundersoft.hz.selfportrait.detect.FaceInfo;
import com.thundersoft.hz.selfportrait.makeup.engine.MakeupEngine;
+import static android.app.Activity.RESULT_OK;
+
public class FilterShowActivity extends FragmentActivity implements OnItemClickListener,
- OnShareTargetSelectedListener, DialogInterface.OnShowListener,
- DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{
+OnShareTargetSelectedListener, DialogInterface.OnShowListener,
+DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{
private String mAction = "";
MasterImage mMasterImage = null;
@@ -174,6 +182,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
private LoadHighresBitmapTask mHiResBitmapTask;
private ParseMpoDataTask mParseMpoTask;
private LoadMpoDataTask mLoadMpoTask;
+ private LoadTruePortraitTask mLoadTruePortraitTask;
private Uri mOriginalImageUri = null;
private ImagePreset mOriginalPreset = null;
@@ -193,6 +202,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
private CategoryAdapter mCategoryVersionsAdapter = null;
private CategoryAdapter mCategoryMakeupAdapter = null;
private CategoryAdapter mCategoryDualCamAdapter = null;
+ private CategoryAdapter mCategoryTruePortraitAdapter = null;
private int mCurrentPanel = MainPanel.LOOKS;
private Vector<FilterUserPresetRepresentation> mVersions =
new Vector<FilterUserPresetRepresentation>();
@@ -249,7 +259,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
long requestId = bundle.getLong(ProcessingService.KEY_REQUEST_ID);
//only handle own request
if (requestId == mRequestId) {
- Uri saveUri = Uri.parse(bundle.getString(ProcessingService.KEY_URL));
+ String url = bundle.getString(ProcessingService.KEY_URL);
+ Uri saveUri = url == null ? null : Uri.parse(url);
boolean releaseDualCam = bundle.getBoolean(ProcessingService.KEY_DUALCAM);
completeSaveImage(saveUri, releaseDualCam);
}
@@ -362,20 +373,31 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
transaction.commitAllowingStateLoss();
}
- public void loadEditorPanel(final FilterRepresentation representation,
- final Editor currentEditor) {
- if (currentEditor.showsActionBar()) {
+ public void loadEditorPanel(final FilterRepresentation representation) {
+ final int currentId = representation.getEditorId();
+
+ // show representation
+ if (mCurrentEditor != null) {
+ mCurrentEditor.detach();
+ }
+ mCurrentEditor = mEditorPlaceHolder.showEditor(currentId);
+
+ if (mCurrentEditor.showsActionBar()) {
setActionBar();
showActionBar(true);
} else {
showActionBar(false);
}
- if (representation.getEditorId() == ImageOnlyEditor.ID) {
- currentEditor.reflectCurrentFilter();
+ if (currentId == ImageOnlyEditor.ID) {
+ mCurrentEditor.reflectCurrentFilter();
+ return;
+ }
+ if (currentId == EditorTruePortraitImageOnly.ID) {
+ mCurrentEditor.reflectCurrentFilter();
+ setActionBarForEffects(mCurrentEditor);
return;
}
- final int currentId = currentEditor.getID();
if (currentId == EditorCrop.ID) {
loadEditorCropPanel();
return;
@@ -416,12 +438,30 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}.run();
return;
}
+ if(currentId == EditorTruePortraitMask.ID) {
+ new Runnable() {
+ @Override
+ public void run() {
+ setActionBarForEffects(mCurrentEditor);
+ TruePortraitMaskEditorPanel panel = new TruePortraitMaskEditorPanel();
+ 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();
+ return;
+ }
+
Runnable showEditor = new Runnable() {
@Override
public void run() {
EditorPanel panel = new EditorPanel();
panel.setEditor(currentId);
- setActionBarForEffects(currentEditor);
+ setActionBarForEffects(mCurrentEditor);
Fragment main =
getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
if (main instanceof MainPanel) {
@@ -464,7 +504,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
MainPanel.FRAGMENT_TAG));
transaction.replace(R.id.main_panel_container, panel,
MainPanel.FRAGMENT_TAG);
- transaction.commit();
+ transaction.commitAllowingStateLoss();
}
}.run();
}
@@ -481,6 +521,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
if (currentPanel instanceof MainPanel) {
((MainPanel) currentPanel).removeEditorPanelFragment();
+ if (mCurrentEditor != null) {
+ mCurrentEditor.detach();
+ }
+ mCurrentEditor = null;
}
}
@@ -537,8 +581,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
public void toggleComparisonButtonVisibility() {
- if (imgComparison.getVisibility() == View.VISIBLE)
- imgComparison.setVisibility(View.GONE);
+ if (imgComparison.getVisibility() == View.VISIBLE)
+ imgComparison.setVisibility(View.GONE);
}
private void showSaveButtonIfNeed() {
@@ -589,10 +633,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
public void setActionBarForEffects(final Editor currentEditor) {
- View view;
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- view = inflater.inflate(R.layout.filtershow_editor_panel, null);
- View editControl = view.findViewById(R.id.controlArea);
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setBackgroundDrawable(new ColorDrawable(getResources()
@@ -625,7 +665,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
});
if (currentEditor != null) {
- currentEditor.setUpEditorUI(editTitle, actionControl, editControl);
+ if(!currentEditor.showsActionBarControls()) {
+ cancelButton.setVisibility(View.GONE);
+ applyButton.setVisibility(View.GONE);
+ }
+ currentEditor.setEditorTitle(editTitle);
currentEditor.reflectCurrentFilter();
if (currentEditor.useUtilityPanel()) {
currentEditor.openUtilityPanel((LinearLayout) actionControl);
@@ -655,6 +699,12 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
int position = adapter.undo();
masterImage.onHistoryItemClick(position);
invalidateViews();
+
+ if(!masterImage.hasFusionApplied()) {
+ masterImage.setFusionUnderlay(null);
+ masterImage.setScaleFactor(1);
+ masterImage.resetTranslation();
+ }
}
public void adjustCompareButton(boolean scaled) {
@@ -683,6 +733,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
fillVersions();
fillMakeup();
fillDualCamera();
+ fillTruePortrait();
}
public void setupStatePanel() {
@@ -805,6 +856,21 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
}
+ private void fillTruePortrait() {
+ FiltersManager filtersManager = FiltersManager.getManager();
+ ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTruePortrait();
+ if (mCategoryTruePortraitAdapter != null) {
+ mCategoryTruePortraitAdapter.clear();
+ }
+ mCategoryTruePortraitAdapter = new CategoryAdapter(this);
+ for (FilterRepresentation representation : filtersRepresentations) {
+ if (representation.getTextId() != 0) {
+ representation.setName(getString(representation.getTextId()));
+ }
+ mCategoryTruePortraitAdapter.add(new Action(this, representation));
+ }
+ }
+
private void fillTrueScanner() {
FiltersManager filtersManager = FiltersManager.getManager();
ArrayList<FilterRepresentation> trueScannerRepresentations = filtersManager.getTrueScanner();
@@ -917,6 +983,16 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mParseMpoTask.execute();
} else {
MasterImage.getImage().setDepthMapLoadingStatus(DdmStatus.DDM_FAILED);
+ Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
+ if (currentPanel instanceof MainPanel) {
+ MainPanel mainPanel = (MainPanel) currentPanel;
+ mainPanel.updateDualCameraButton();
+ }
+ }
+
+ if(TruePortraitNativeEngine.getInstance().isLibLoaded()) {
+ mLoadTruePortraitTask = new LoadTruePortraitTask();
+ mLoadTruePortraitTask.execute(uri);
}
}
@@ -979,6 +1055,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
return mCategoryDualCamAdapter;
}
+ public CategoryAdapter getCategoryTruePortraitAdapter() {
+ return mCategoryTruePortraitAdapter;
+ }
+
public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
if (filterRepresentation == null) {
return;
@@ -998,8 +1078,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
return;
}
if (!(filterRepresentation instanceof FilterRotateRepresentation)
- && !(filterRepresentation instanceof FilterMirrorRepresentation)
- && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
+ && !(filterRepresentation instanceof FilterMirrorRepresentation)
+ && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
return;
}
if (filterRepresentation instanceof FilterUserPresetRepresentation
@@ -1077,12 +1157,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
useFilterRepresentation(representation);
- // show representation
- if (mCurrentEditor != null) {
- mCurrentEditor.detach();
- }
- mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
- loadEditorPanel(representation, mCurrentEditor);
+ loadEditorPanel(representation);
}
public Editor getEditor(int editorID) {
@@ -1114,6 +1189,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryMakeupAdapter.reflectImagePreset(preset);
}
mCategoryDualCamAdapter.reflectImagePreset(preset);
+ mCategoryTruePortraitAdapter.reflectImagePreset(preset);
}
public View getMainStatePanelContainer(int id) {
@@ -1156,6 +1232,16 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
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()
@@ -1180,32 +1266,37 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
}
- private class ParseMpoDataTask extends AsyncTask<Void, Void, byte[]> {
+ private class ParseMpoDataTask extends AsyncTask<Void, Void, Void> {
+ private byte[] mPrimaryImgData = null;
+ private byte[] mAuxImgData = null;
+
@Override
protected void onPreExecute() {
MasterImage.getImage().setDepthMapLoadingStatus(DdmStatus.DDM_PARSING);
}
@Override
- protected byte[] doInBackground(Void... params) {
+ protected Void doInBackground(Void... params) {
MpoParser parser = MpoParser.parse(FilterShowActivity.this, MasterImage.getImage().getUri());
- return parser.readImgData(false);
+ mPrimaryImgData = parser.readImgData(true);
+ mAuxImgData = parser.readImgData(false);
+ return null;
}
@Override
- protected void onPostExecute(byte[] result) {
- if(result == null) {
+ protected void onPostExecute(Void result) {
+ if(mPrimaryImgData == null ||
+ mAuxImgData == null) {
// parse failed
MasterImage.getImage().setDepthMapLoadingStatus(DdmStatus.DDM_FAILED);
+ Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
+ if (currentPanel instanceof MainPanel) {
+ MainPanel mainPanel = (MainPanel) currentPanel;
+ mainPanel.updateDualCameraButton();
+ }
} else {
mLoadMpoTask = new LoadMpoDataTask();
- mLoadMpoTask.execute(result);
- }
-
- Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
- if (currentPanel instanceof MainPanel) {
- MainPanel mainPanel = (MainPanel) currentPanel;
- mainPanel.updateDualCameraButton();
+ mLoadMpoTask.execute(mPrimaryImgData, mAuxImgData);
}
}
}
@@ -1218,12 +1309,17 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
@Override
protected Boolean doInBackground(byte[]... params) {
- return MasterImage.getImage().loadMpo(params[0]);
+ return MasterImage.getImage().loadMpo(params[0], params[1]);
}
@Override
protected void onPostExecute(Boolean result) {
MasterImage.getImage().setDepthMapLoadingStatus(result?DdmStatus.DDM_LOADED:DdmStatus.DDM_FAILED);
+ Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
+ if (currentPanel instanceof MainPanel) {
+ MainPanel mainPanel = (MainPanel) currentPanel;
+ mainPanel.updateDualCameraButton();
+ }
stopLoadingIndicator();
}
}
@@ -1259,7 +1355,40 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
if(mLoadingDialog != null && mLoadingDialog.isShowing()) {
mLoadingDialog.dismiss();
}
- }
+ }
+
+ private class LoadTruePortraitTask extends AsyncTask<Uri, Void, Boolean> {
+
+ @Override
+ protected Boolean doInBackground(Uri... params) {
+ boolean result = false;
+ Bitmap src = ImageLoader.loadBitmap(FilterShowActivity.this, params[0], null);
+ FaceDetect fDetect = new FaceDetect();
+ fDetect.initialize();
+ FaceInfo[] faceInfos = fDetect.dectectFeatures(src);
+ fDetect.uninitialize();
+
+ if(faceInfos != null && faceInfos.length > 0) {
+ Rect[] faces = new Rect[faceInfos.length];
+ for(int i=0; i<faceInfos.length; i++) {
+ faces[i] = faceInfos[i].face;
+ }
+
+ result = TruePortraitNativeEngine.getInstance().init(FilterShowActivity.this, src, faces);
+ } else {
+ TruePortraitNativeEngine.getInstance().setFacesDetected(false);
+ }
+
+ src.recycle();
+ src = null;
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ }
+ }
private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
int mBitmapSize;
@@ -1333,6 +1462,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryGeometryAdapter.imageLoaded();
mCategoryFiltersAdapter.imageLoaded();
mCategoryDualCamAdapter.imageLoaded();
+ mCategoryTruePortraitAdapter.imageLoaded();
if(mCategoryMakeupAdapter != null) {
mCategoryMakeupAdapter.imageLoaded();
}
@@ -1392,6 +1522,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mLoadMpoTask.cancel(false);
}
+ if(mLoadTruePortraitTask != null) {
+ mLoadTruePortraitTask.cancel(false);
+ }
+
mUserPresetsManager.close();
unregisterReceiver(mHandlerReceiver);
doUnbindService();
@@ -1486,11 +1620,15 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
menu.clear();
getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
mShareActionProvider = (ShareActionProvider) menu.findItem(
- R.id.menu_share).getActionProvider();
+ R.id.menu_share).getActionProvider();
mShareActionProvider.setShareIntent(getDefaultShareIntent());
mShareActionProvider.setOnShareTargetSelectedListener(this);
mMenu = menu;
setupMenu();
+
+ if(mCurrentEditor != null) {
+ mCurrentEditor.onPrepareOptionsMenu(menu);
+ }
return true;
}
@@ -1531,7 +1669,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- /*case R.id.undoButton: {
+ /*case R.id.undoButton: {
HistoryManager adapter = mMasterImage.getHistory();
int position = adapter.undo();
mMasterImage.onHistoryItemClick(position);
@@ -1546,26 +1684,26 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
invalidateViews();
return true;
}*/
- case R.id.resetHistoryButton: {
- resetHistory();
- return true;
- }
- /*case R.id.showImageStateButton: {
+ case R.id.resetHistoryButton: {
+ resetHistory();
+ return true;
+ }
+ /*case R.id.showImageStateButton: {
toggleImageStatePanel();
return true;
}*/
- case R.id.exportFlattenButton: {
- showExportOptionsDialog();
- return true;
- }
- case android.R.id.home: {
- saveImage();
- return true;
- }
- case R.id.manageUserPresets: {
- manageUserPresets();
- return true;
- }
+ case R.id.exportFlattenButton: {
+ showExportOptionsDialog();
+ return true;
+ }
+ case android.R.id.home: {
+ saveImage();
+ return true;
+ }
+ case R.id.manageUserPresets: {
+ manageUserPresets();
+ return true;
+ }
}
return false;
}
@@ -1862,18 +2000,18 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
R.string.save_before_exit);
mBackAlertDialogBuilder.setPositiveButton(mPopUpText,
new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- done();
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ done();
+ }
+ });
mBackAlertDialogBuilder.setNegativeButton(mCancel,
new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
}
public void cannotLoadImage() {
@@ -1913,8 +2051,13 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
} else if (requestCode == SELECT_FUSION_UNDERLAY) {
Uri underlayImageUri = data.getData();
// find fusion representation
- EditorDualCamFusion editor = (EditorDualCamFusion)getEditor(EditorDualCamFusion.ID);
- editor.setUnderlayImageUri(underlayImageUri);
+ if(mCurrentEditor instanceof EditorDualCamFusion) {
+ EditorDualCamFusion editor = (EditorDualCamFusion)mCurrentEditor;
+ editor.setUnderlayImageUri(underlayImageUri);
+ } else if (mCurrentEditor instanceof EditorTruePortraitFusion) {
+ EditorTruePortraitFusion editor = (EditorTruePortraitFusion)mCurrentEditor;
+ editor.setUnderlayImageUri(underlayImageUri);
+ }
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
index 10cadcfd2..82129c2c6 100644
--- a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
+++ b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
@@ -16,18 +16,18 @@
package com.android.gallery3d.filtershow.cache;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.PorterDuff;
+import android.graphics.Color;
import android.util.Log;
import com.android.gallery3d.filtershow.pipeline.Buffer;
import com.android.gallery3d.filtershow.pipeline.CacheProcessing;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-
public class BitmapCache {
private static final String LOGTAG = "BitmapCache";
private HashMap<Long, ArrayList<WeakReference<Bitmap>>>
@@ -207,8 +207,8 @@ public class BitmapCache {
public synchronized Bitmap getBitmapCopy(Bitmap source, int type) {
Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight(), type);
+ bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(source, 0, 0, null);
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/category/Action.java b/src/com/android/gallery3d/filtershow/category/Action.java
index 9c0587bfc..75982d851 100644
--- a/src/com/android/gallery3d/filtershow/category/Action.java
+++ b/src/com/android/gallery3d/filtershow/category/Action.java
@@ -30,6 +30,7 @@ import android.widget.ListAdapter;
import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.cache.BitmapCache;
import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.pipeline.RenderingRequest;
@@ -121,6 +122,16 @@ public class Action implements RenderingRequestCaller {
if (getType() == Action.ADD_ACTION) {
return;
}
+
+ if(mRepresentation.getOverlayOnly()) {
+ mImageFrame = imageFrame;
+ int w = mImageFrame.width();
+ int h = mImageFrame.height();
+ mImage = MasterImage.getImage().getBitmapCache().getBitmap(w, h, BitmapCache.ICON);
+ drawOverlay(true);
+ return;
+ }
+
Bitmap temp = MasterImage.getImage().getTemporaryThumbnailBitmap();
if (temp != null) {
mImage = temp;
@@ -175,14 +186,7 @@ public class Action implements RenderingRequestCaller {
canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG));
}
- @Override
- public void available(RenderingRequest request) {
- clearBitmap();
- mImage = request.getBitmap();
- if (mImage == null) {
- mImageFrame = null;
- return;
- }
+ private void drawOverlay(boolean scale) {
if (mRepresentation.getOverlayId() != 0 && mOverlayBitmap == null) {
mOverlayBitmap = BitmapFactory.decodeResource(
mContext.getResources(),
@@ -196,9 +200,22 @@ public class Action implements RenderingRequestCaller {
} else {
Canvas canvas = new Canvas(mImage);
canvas.drawARGB(128, 0, 0, 0);
- drawCenteredImage(mOverlayBitmap, mImage, false);
+ drawCenteredImage(mOverlayBitmap, mImage, scale);
}
}
+ }
+
+ @Override
+ public void available(RenderingRequest request) {
+ clearBitmap();
+ mImage = request.getBitmap();
+ if (mImage == null) {
+ mImageFrame = null;
+ return;
+ }
+
+ drawOverlay(false);
+
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
diff --git a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
index 4062bf0ef..6c4f9fe87 100644
--- a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
+++ b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
@@ -80,15 +80,18 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
mSelectedPosition = 0;
mAddButtonText = getContext().getString(R.string.filtershow_add_button_looks);
}
-// if (category == MainPanel.MAKEUP) {
-// mSelectedPosition = 0;
-// }
+ // if (category == MainPanel.MAKEUP) {
+ // mSelectedPosition = 0;
+ // }
if (category == MainPanel.BORDERS) {
mSelectedPosition = 0;
}
if (category == MainPanel.DUALCAM) {
mSelectedPosition = 0;
}
+ if (category == MainPanel.TRUEPORTRAIT) {
+ mSelectedPosition = 0;
+ }
if (category == MainPanel.TRUESCANNER) {
mSelectedPosition = 0;
@@ -149,6 +152,10 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
return (Integer) v.getTag() == mSelectedPosition;
}
+ public int getCurrentSelection() {
+ return mSelectedPosition;
+ }
+
private void invalidateView(int position) {
View child = null;
if (mContainer instanceof ListView) {
@@ -235,6 +242,11 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
if (pos != -1) {
rep = preset.getFilterRepresentation(pos);
}
+ } else if (mCategory == MainPanel.TRUEPORTRAIT) {
+ int pos = preset.getPositionForType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ if (pos != -1) {
+ rep = preset.getFilterRepresentation(pos);
+ }
} else if (mCategory == MainPanel.FILTERS || mCategory == MainPanel.MAKEUP) {
selected = UNKNOWN_INDEX;
}
diff --git a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
index cbe38c8e6..3b91f024e 100644
--- a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
@@ -88,6 +88,15 @@ public class CategoryPanel extends Fragment implements View.OnClickListener {
mAdapter.initializeSelection(MainPanel.DUALCAM);
}
activity.updateCategories();
+ break;
+ }
+ case MainPanel.TRUEPORTRAIT: {
+ mAdapter = activity.getCategoryTruePortraitAdapter();
+ if (mAdapter != null) {
+ mAdapter.initializeSelection(MainPanel.TRUEPORTRAIT);
+ }
+ activity.updateCategories();
+ break;
}
case MainPanel.TRUESCANNER: {
mAdapter = activity.getCategoryTrueScannerAdapter();
diff --git a/src/com/android/gallery3d/filtershow/category/GeometryPanel.java b/src/com/android/gallery3d/filtershow/category/GeometryPanel.java
index b0d39175c..7772f1838 100644..100755
--- a/src/com/android/gallery3d/filtershow/category/GeometryPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/GeometryPanel.java
@@ -79,7 +79,9 @@ public class GeometryPanel extends BasicGeometryPanel {
int size = mButtons.length;
for (int i = 0; i < size; i++) {
ImageButton view = mButtons[i];
- view.setImageDrawable(res.getDrawable(mFiltersRepresentations.get(i).getOverlayId()));
+ if (mFiltersRepresentations.size() > 0) {
+ view.setImageDrawable(res.getDrawable(mFiltersRepresentations.get(i).getOverlayId()));
+ }
// ues tag to store index.
view.setTag(i);
view.setOnClickListener(mOnClickListener);
@@ -93,7 +95,9 @@ public class GeometryPanel extends BasicGeometryPanel {
int size = mTextViews.length;
for (int i = 0; i < size; i++) {
TextView view = mTextViews[i];
- view.setText(res.getString(mFiltersRepresentations.get(i).getTextId()));
+ if (mFiltersRepresentations.size() > 0) {
+ view.setText(res.getString(mFiltersRepresentations.get(i).getTextId()));
+ }
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/category/MainPanel.java b/src/com/android/gallery3d/filtershow/category/MainPanel.java
index f4b22e37b..4c909789d 100644
--- a/src/com/android/gallery3d/filtershow/category/MainPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/MainPanel.java
@@ -17,6 +17,8 @@
package com.android.gallery3d.filtershow.category;
import android.content.res.Configuration;
+import android.content.Context;
+import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
@@ -38,7 +40,11 @@ import com.android.gallery3d.filtershow.filters.SimpleMakeupImageFilter;
import com.android.gallery3d.filtershow.filters.TrueScannerActs;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.state.StatePanel;
+import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine.DdmStatus;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelegate {
@@ -55,6 +61,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
private ImageButton trueScannerButton;
private ImageButton hazeBusterButton;
private ImageButton seeStraightButton;
+ private ImageButton truePortraitButton;
public static final String FRAGMENT_TAG = "MainPanel";
public static final String EDITOR_TAG = "coming-from-editor-panel";
@@ -68,6 +75,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
public static final int TRUESCANNER = 7;
public static final int HAZEBUSTER = 8;
public static final int SEESTRAIGHT = 9;
+ public static final int TRUEPORTRAIT = 10;
private int mCurrentSelected = -1;
private int mPreviousToggleVersions = -1;
@@ -104,6 +112,10 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
dualCamButton.setSelected(value);
break;
}
+ case TRUEPORTRAIT: {
+ truePortraitButton.setSelected(value);
+ break;
+ }
case TRUESCANNER: {
if (trueScannerButton != null) {
trueScannerButton.setSelected(value);
@@ -138,7 +150,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ Bundle savedInstanceState) {
mMainView = (LinearLayout) inflater.inflate(
R.layout.filtershow_main_panel, null, false);
@@ -171,6 +183,10 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
geometryButton = (ImageButton) bottomPanel.findViewById(R.id.geometryButton);
filtersButton = (ImageButton) bottomPanel.findViewById(R.id.colorsButton);
dualCamButton = (ImageButton) bottomPanel.findViewById(R.id.dualCamButton);
+ if(!DualCameraNativeEngine.getInstance().isLibLoaded()) {
+ dualCamButton.setVisibility(View.GONE);
+ }
+
if (SimpleMakeupImageFilter.HAS_TS_MAKEUP) {
makeupButton = (ImageButton) bottomPanel.findViewById(R.id.makeupButton);
makeupButton.setVisibility(View.VISIBLE);
@@ -199,6 +215,11 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
seeStraightButton.setVisibility(View.GONE);
}
+ truePortraitButton = (ImageButton) bottomPanel.findViewById(R.id.truePortraitButton);
+ if(!TruePortraitNativeEngine.getInstance().isLibLoaded()) {
+ truePortraitButton.setVisibility(View.GONE);
+ }
+
looksButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -230,9 +251,42 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
}
});
+ truePortraitButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ Context context = getActivity();
+ boolean skipIntro = GalleryUtils.getBooleanPref(context,
+ context.getString(R.string.pref_trueportrait_intro_show_key), false);
+ final boolean facesDetected = TruePortraitNativeEngine.getInstance().facesDetected();
+ if(skipIntro && facesDetected) {
+ showPanel(TRUEPORTRAIT);
+ } else if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.trueportrait, R.string.trueportrait_intro,
+ R.string.pref_trueportrait_intro_show_key) {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if(facesDetected) {
+ showPanel(TRUEPORTRAIT);
+ } else {
+ v.setEnabled(false);
+ TruePortraitNativeEngine.getInstance().showNoFaceDetectedDialog(getFragmentManager());
+ }
+ }
+ };
+ dialog.show(getFragmentManager(), "trueportrait_intro");
+ } else {
+ v.setEnabled(false);
+ TruePortraitNativeEngine.getInstance().showNoFaceDetectedDialog(getFragmentManager());
+ }
+ }
+ });
+
trueScannerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+
showPanel(TRUESCANNER);
}
});
@@ -444,6 +498,19 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
}
}
+ public void loadCategoryTruePortraitPanel() {
+ if (mCurrentSelected == TRUEPORTRAIT) {
+ return;
+ }
+ boolean fromRight = isRightAnimation(TRUEPORTRAIT);
+ selection(mCurrentSelected, false);
+ CategoryPanel categoryPanel = new CategoryPanel();
+ categoryPanel.setAdapter(TRUEPORTRAIT);
+ setCategoryFragment(categoryPanel, fromRight);
+ mCurrentSelected = TRUEPORTRAIT;
+ selection(mCurrentSelected, true);
+ }
+
public void showPanel(int currentPanel) {
FilterShowActivity activity = (FilterShowActivity) getActivity();
switch (currentPanel) {
@@ -487,6 +554,10 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
loadCategoryMakeupPanel();
break;
}
+ case TRUEPORTRAIT: {
+ loadCategoryTruePortraitPanel();
+ break;
+ }
}
if (currentPanel > 0) {
activity.adjustCompareButton(true);
diff --git a/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java b/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java
new file mode 100644
index 000000000..03935edc0
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.category;
+
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class TruePortraitMaskEditorPanel extends Fragment {
+ private View mMainView;
+ private EditorTruePortraitMask mEditor;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ FilterShowActivity filterShowActivity = (FilterShowActivity) context;
+ mEditor = (EditorTruePortraitMask) filterShowActivity.getEditor(EditorTruePortraitMask.ID);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mMainView = inflater.inflate(R.layout.filtershow_trueportrait_editor_panel, container, false);
+ mEditor.setUpEditorUI(mMainView, null);
+ return mMainView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Context context = getActivity();
+ boolean skipIntro = GalleryUtils.getBooleanPref(context,
+ context.getString(R.string.pref_trueportrait_edit_intro_show_key), false);
+ if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.trueportrait_touch_up, R.string.trueportrait_edit_intro,
+ R.string.pref_trueportrait_edit_intro_show_key);
+ dialog.setCancelable(false);
+ dialog.show(getFragmentManager(), "trueportrait_edit_intro");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ if (mEditor != null) {
+ mEditor.detach();
+ }
+ super.onDetach();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/controller/BasicSlider.java b/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
index eb6a491f4..d0d0fcaa6 100644
--- a/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
+++ b/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -41,7 +40,7 @@ public class BasicSlider implements Control {
mParameter = (ParameterInteger) parameter;
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LinearLayout lp = (LinearLayout) inflater.inflate(
+ View lp = inflater.inflate(
R.layout.filtershow_seekbar, container, true);
mSeekBar = (SeekBar) lp.findViewById(R.id.primarySeekBar);
mSeekBar.setVisibility(View.VISIBLE);
diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java
index f68689388..e5d9e486e 100644
--- a/src/com/android/gallery3d/filtershow/editors/Editor.java
+++ b/src/com/android/gallery3d/filtershow/editors/Editor.java
@@ -16,10 +16,11 @@
package com.android.gallery3d.filtershow.editors;
+import java.util.ArrayList;
+import java.util.Collection;
+
import android.content.Context;
import android.content.res.Configuration;
-import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -41,9 +42,6 @@ import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
-import java.util.ArrayList;
-import java.util.Collection;
-
/**
* Base class for Editors Must contain a mImageShow and a top level view
*/
@@ -102,6 +100,10 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
return !showsSeekBar();
}
+ public boolean showsActionBarControls() {
+ return showsActionBar();
+ }
+
/*public void setUpEditorUI(View actionButton, View editControl,
Button editTitle, Button stateButton) {
mEditTitle = editTitle;
@@ -116,14 +118,12 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mFilterTitle = stateButton;
MasterImage.getImage().resetGeometryImages(false);
mEditControl = editControl;
- setUtilityPanelUI(null, editControl);
+ setEditPanelUI(editControl);
}
- public void setUpEditorUI(Button editTitle, View actionButton,
- View editControl) {
+ public void setEditorTitle(Button editTitle) {
mEditTitle = editTitle;
mButton = editTitle;
- setUtilityPanelUI(actionButton, editControl);
}
public void setBasicFilterUI(TextView textFilterName,
@@ -132,21 +132,18 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mBasicFilterValue = textFilterValue;
}
- public boolean showsPopupIndicator() {
+ public boolean showsPopupIndicator() {
return false;
}
/**
- * @param actionButton the would be the area for menu etc
* @param editControl this is the black area for sliders etc
*/
- public void setUtilityPanelUI(View actionButton, View editControl) {
-
- AttributeSet aset;
+ public void setEditPanelUI(View editControl) {
Context context = editControl.getContext();
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LinearLayout lp = (LinearLayout) inflater.inflate(
+ View lp = inflater.inflate(
R.layout.filtershow_seekbar, (ViewGroup) editControl, true);
mSeekBar = (SeekBar) lp.findViewById(R.id.primarySeekBar);
mSeekBar.setOnSeekBarChangeListener(this);
@@ -298,7 +295,7 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
String[] split = text.split("[+-]");
int length = split.length;
if (length == 2)
- mBasicFilterValue.setText(split[1] != null ? split[1] : "");
+ mBasicFilterValue.setText(split[1] != null ? split[1] : "");
mBasicFilterText.setVisibility(View.VISIBLE);
mBasicFilterValue.setVisibility(View.VISIBLE);
mButton.setVisibility(View.INVISIBLE);
@@ -380,4 +377,12 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mImageShow.detach();
}
}
+
+ public void resume() {
+
+ }
+
+ public void onPrepareOptionsMenu(Menu menu) {
+
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
index 0cc2ee322..664aa6c40 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
@@ -168,12 +168,11 @@ public class EditorChanSat extends ParametricEditor implements OnSeekBarChangeLi
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
- mActionButton = actionButton;
mEditControl = editControl;
mEditTitle.setCompoundDrawables(null, null, null, null);
LinearLayout group = (LinearLayout) editControl;
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
index 71f4dcb58..90252859f 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
@@ -17,15 +17,9 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -34,9 +28,7 @@ import android.widget.SeekBar;
import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
-import com.android.gallery3d.filtershow.controller.BitmapCaller;
import com.android.gallery3d.filtershow.controller.ColorChooser;
-import com.android.gallery3d.filtershow.controller.FilterView;
import com.android.gallery3d.filtershow.filters.FilterColorBorderRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.ImageFilterColorBorder;
@@ -187,9 +179,9 @@ public class EditorColorBorder extends ParametricEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
index e4db1f23d..425915736 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
@@ -145,8 +145,8 @@ public class EditorCrop extends Editor implements EditorInfo {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton,editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
setMenuIcon(true);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCurves.java b/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
index 475c86422..e305f7abd 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
@@ -61,8 +61,8 @@ public class EditorCurves extends Editor {
}
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton,editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
setMenuIcon(true);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
index 20d788510..5298cab1c 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
@@ -241,9 +241,9 @@ public class EditorDraw extends ParametricEditor implements FilterView {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
index d20b15511..2371ccb15 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
@@ -76,7 +76,7 @@ public class EditorDualCamFusion extends ImageOnlyEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
editControl.setVisibility(View.GONE);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
index 3624a6e10..25000117b 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
@@ -140,9 +140,9 @@ public class EditorGrad extends ParametricEditor
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java b/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
index 26ecd4f49..50377c1ee 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
@@ -31,8 +31,8 @@ public class EditorMakeup extends BasicEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton, editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
if (mSeekBar != null) {
mSeekBar.setVisibility(View.INVISIBLE);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
index 34f711df9..00c0aa795 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
@@ -22,6 +22,7 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -68,10 +69,6 @@ public class EditorPanel extends Fragment {
int position = adapter.undo();
masterImage.onHistoryItemClick(position);
((FilterShowActivity)getActivity()).invalidateViews();
-
- if(!masterImage.hasFusionApplied()) {
- masterImage.setFusionUnderlay(null);
- }
}
@Override
@@ -100,6 +97,14 @@ public class EditorPanel extends Fragment {
}
@Override
+ public void onResume() {
+ if (mEditor != null) {
+ mEditor.resume();
+ }
+ super.onResume();
+ }
+
+ @Override
public void onDetach() {
if (mEditor != null) {
mEditor.detach();
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java
new file mode 100644
index 000000000..a09e216b5
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+
+public class EditorTruePortraitBasic extends BasicEditor {
+ private static final String LOGTAG = "EditorTruePortraitBasic";
+ public static final int ID = R.id.editorTruePortraitBasic;
+
+ public EditorTruePortraitBasic() {
+ super(ID);
+ }
+
+ @Override
+ public boolean showsActionBar() {
+ return true;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait, accessoryViewList);
+
+ View editMask = accessoryViewList.findViewById(R.id.editMask);
+ editMask.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java
new file mode 100644
index 000000000..cfeea1375
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageTruePortraitFusion;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class EditorTruePortraitFusion extends Editor {
+ public static final String TAG = "EditorTruePortraitFusion";
+ public static final int ID = R.id.editorTruePortraitFusion;
+
+ protected ImageTruePortraitFusion mImageFusion;
+ private Uri mUnderlayUri = Uri.EMPTY;
+
+ public EditorTruePortraitFusion() {
+ super(ID);
+ }
+
+ @Override
+ public boolean showsActionBar() {
+ return true;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ if (mImageFusion == null) {
+ mImageFusion = new ImageTruePortraitFusion(context);
+ }
+ mView = mImageShow = mImageFusion;
+ mImageFusion.setEditor(this);
+ }
+
+ @Override
+ public void setEditPanelUI(View editControl) {
+ ViewGroup controlContainer = (ViewGroup)editControl;
+ controlContainer.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ View controls = inflater.inflate(R.layout.filtershow_seekbar, controlContainer);
+ View seekbar = controls.findViewById(R.id.primarySeekBar);
+ seekbar.setVisibility(View.GONE);
+ View saveButton = controls.findViewById(R.id.slider_save);
+ if (saveButton != null) {
+ saveButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ finalApplyCalled();
+ activity.leaveSeekBarPanel();
+ }
+ });
+ }
+ View cancelButton = controls.findViewById(R.id.slider_cancel);
+ if (cancelButton != null) {
+ cancelButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ activity.cancelCurrentFilter();
+ activity.leaveSeekBarPanel();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void openUtilityPanel(final LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait_fusion, accessoryViewList);
+
+ View pickUnderlayBtn = accessoryViewList.findViewById(R.id.pick_underlay);
+ pickUnderlayBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ MasterImage.getImage().getActivity().pickImage(FilterShowActivity.SELECT_FUSION_UNDERLAY);
+ }
+ });
+
+ View editMaskBtn = accessoryViewList.findViewById(R.id.editMask);
+ editMaskBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+
+ // Look for previous underlay
+ String fusionUnderlay = GalleryUtils.getStringPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_underlay_key), null);
+ Uri fusionUri = Uri.EMPTY;
+
+ if(fusionUnderlay != null) {
+ fusionUri = Uri.parse(fusionUnderlay);
+ if(!uriExists(mContext, fusionUri))
+ fusionUri = Uri.EMPTY;
+ }
+
+ setUnderlayImageUri(fusionUri);
+ }
+
+ @Override
+ public void resume() {
+ if(mUnderlayUri.equals(Uri.EMPTY)) {
+ // No underlay set.
+ boolean skipIntro = GalleryUtils.getBooleanPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_intro_show_key), false);
+ if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.fusion_pick_background, R.string.trueportrait_fusion_intro,
+ R.string.pref_trueportrait_fusion_intro_show_key) {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ MasterImage.getImage().getActivity().pickImage(FilterShowActivity.SELECT_FUSION_UNDERLAY);
+ }
+ };
+ FragmentManager fm = ((FilterShowActivity)mContext).getSupportFragmentManager();
+ dialog.setCancelable(false);
+ dialog.show(fm, "trueportrait_fusion_intro");
+ }
+ }
+ }
+
+ public void setUnderlayImageUri(Uri uri) {
+ mUnderlayUri = uri;
+ FilterRepresentation filter = getLocalRepresentation();
+ if(filter instanceof FilterTruePortraitFusionRepresentation) {
+ mImageFusion.setUnderlay(uri);
+ commitLocalRepresentation();
+
+ // save fusion underlay uri
+ GalleryUtils.setStringPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_underlay_key),
+ (uri != null)?uri.toString():null);
+ }
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep != null && rep instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation fusionRep = (FilterTruePortraitFusionRepresentation) rep;
+ mImageFusion.setRepresentation(fusionRep);
+ }
+ }
+
+ private boolean uriExists(Context context, Uri uri) {
+ try {
+ InputStream stream = context.getContentResolver().openInputStream(uri);
+ stream.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java
new file mode 100644
index 000000000..781b2e417
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageShow;
+
+public class EditorTruePortraitImageOnly extends Editor {
+ private static final String LOGTAG = "EditorTruePortraitImageOnly";
+ public static final int ID = R.id.editorTruePortraitImageOnly;
+
+ public EditorTruePortraitImageOnly() {
+ super(ID);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ mView = mImageShow = new ImageShow(context);
+ }
+
+ @Override
+ public boolean showsSeekBar() {
+ return false;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait, accessoryViewList);
+
+ View editMask = accessoryViewList.findViewById(R.id.editMask);
+ editMask.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java
new file mode 100644
index 000000000..7c5842f7f
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+
+import android.content.Context;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.ToggleButton;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.imageshow.ImageTruePortraitMask;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.ui.AlertMsgDialog;
+
+public class EditorTruePortraitMask extends Editor {
+ private static final String LOGTAG = "EditorTruePortraitMask";
+ public static final int ID = R.id.editorTruePortraitMask;
+
+ private AlertMsgDialog mHelpDialog;
+ private ImageTruePortraitMask mTruePortraitImage;
+ private ToggleButton mForeground;
+ private ToggleButton mBackground;
+ private ImageButton mExitButton;
+ private ImageButton mApplyButton;
+ private View mMaskUndoButton;
+ private View mBrushSizeButton;
+ private View[] mBrushSizes = new View[3];
+ private int mBrushIndex = 0;
+
+ private static final int[] BRUSH_SIZES = {
+ 10, 30, 50
+ };
+
+ private OnClickListener mDoneClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if(view.getId() == R.id.done) {
+ finalApplyCalled();
+ }
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ activity.backToMain();
+ activity.setActionBar();
+ }
+ };
+
+ public EditorTruePortraitMask() {
+ super(ID);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ unpack(R.id.truePortraitMaskEditor, R.layout.filtershow_trueportrait_mask_editor);
+ mTruePortraitImage = (ImageTruePortraitMask)mImageShow;
+ mTruePortraitImage.setEditor(this);
+ }
+
+ @Override
+ public boolean showsSeekBar() {
+ return false;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait_mask, accessoryViewList);
+
+ mMaskUndoButton = accessoryViewList.findViewById(R.id.maskUndo);
+ mMaskUndoButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mTruePortraitImage.undoLastEdit();
+ }
+ });
+ refreshUndoButton();
+
+ View maskHelp = accessoryViewList.findViewById(R.id.maskHelp);
+ maskHelp.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if(mHelpDialog == null)
+ mHelpDialog = new AlertMsgDialog(R.string.help, R.string.trueportrait_edit_help);
+
+ FragmentManager fm = ((FilterShowActivity)mContext).getSupportFragmentManager();
+ mHelpDialog.show(fm, "tp_edit_help");
+ }
+ });
+
+ mForeground = (ToggleButton)accessoryViewList.findViewById(R.id.maskForeground);
+ mForeground.setChecked(true);
+ mForeground.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if(mBackground.isChecked() == isChecked)
+ mBackground.toggle();
+ mTruePortraitImage.invalidate();
+ showToast();
+ }
+ });
+
+ mBackground = (ToggleButton)accessoryViewList.findViewById(R.id.maskBackground);
+ mBackground.setChecked(false);
+ mBackground.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if(mForeground.isChecked() == isChecked)
+ mForeground.toggle();
+ }
+ });
+ }
+
+ @Override
+ public void setUpEditorUI(View editControl, Button stateButton) {
+ mExitButton = (ImageButton) editControl.findViewById(R.id.cancel);
+ mApplyButton = (ImageButton) editControl.findViewById(R.id.done);
+ mExitButton.setOnClickListener(mDoneClickListener);
+ mApplyButton.setOnClickListener(mDoneClickListener);
+
+ mBrushSizeButton = editControl.findViewById(R.id.brush_size);
+ mBrushSizeButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ cycleBrushSize();
+ }
+ });
+
+ mBrushSizes[0] = editControl.findViewById(R.id.brush_size_sm);
+ mBrushSizes[0].setSelected(false);
+ mBrushSizes[1] = editControl.findViewById(R.id.brush_size_med);
+ mBrushSizes[1].setSelected(false);
+ mBrushSizes[2] = editControl.findViewById(R.id.brush_size_large);
+ mBrushSizes[2].setSelected(false);
+
+ mBrushSizes[mBrushIndex].setSelected(true);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+
+ @Override
+ public void finalApplyCalled() {
+ mTruePortraitImage.applyMaskUpdates();
+ MasterImage.getImage().invalidateFiltersOnly();
+ }
+
+ private void showToast() {
+ Toast toast;
+ if(isBackgroundMode()) {
+ toast = Toast.makeText(mContext, R.string.trueportrait_edit_background_toast, Toast.LENGTH_SHORT);
+ } else {
+ toast = Toast.makeText(mContext, R.string.trueportrait_edit_foreground_toast, Toast.LENGTH_SHORT);
+ }
+
+ toast.show();
+ }
+
+ public void refreshUndoButton() {
+ mMaskUndoButton.setEnabled(mTruePortraitImage.canUndoEdit());
+ }
+
+ public boolean isBackgroundMode() {
+ return mBackground.isChecked();
+ }
+
+ public int cycleBrushSize() {
+ mBrushSizes[mBrushIndex].setSelected(false);
+ mBrushIndex = (mBrushIndex+1)%BRUSH_SIZES.length;
+ mBrushSizes[mBrushIndex].setSelected(true);
+ return getBrushSize();
+ }
+
+ public int getBrushSize() {
+ return BRUSH_SIZES[mBrushIndex];
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
index 8b5fcb505..e3dd7ff67 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
@@ -187,12 +187,11 @@ public class EditorVignette extends ParametricEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
- mActionButton = actionButton;
mEditControl = editControl;
mEditTitle.setCompoundDrawables(null, null, null, null);
LinearLayout group = (LinearLayout) editControl;
diff --git a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
index c13c9f822..3ee36134f 100644
--- a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
+++ b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
@@ -135,7 +135,8 @@ public class ParametricEditor extends Editor {
public void reflectCurrentFilter() {
super.reflectCurrentFilter();
if (getLocalRepresentation() != null
- && getLocalRepresentation() instanceof FilterBasicRepresentation) {
+ && getLocalRepresentation() instanceof FilterBasicRepresentation
+ && mControl != null) {
FilterBasicRepresentation interval = (FilterBasicRepresentation) getLocalRepresentation();
mControl.setPrameter(interval);
}
@@ -164,8 +165,7 @@ public class ParametricEditor extends Editor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- mActionButton = actionButton;
+ public void setEditPanelUI(View editControl) {
mEditControl = editControl;
FilterRepresentation rep = getLocalRepresentation();
Parameter param = getParameterToEdit(rep);
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index e6ac0a6ef..b9c24fc27 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -21,6 +21,8 @@ import android.graphics.Color;
import android.util.Log;
import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitBasic;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitImageOnly;
import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
@@ -42,6 +44,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
protected ArrayList<FilterRepresentation> mTrueScanner = new ArrayList<FilterRepresentation>();
protected ArrayList<FilterRepresentation> mHazeBuster = new ArrayList<FilterRepresentation>();
protected ArrayList<FilterRepresentation> mSeeStraight = new ArrayList<FilterRepresentation>();
+ protected ArrayList<FilterRepresentation> mTruePortrait = new ArrayList<FilterRepresentation>();
private static int mImageBorderSize = 4; // in percent
protected void init() {
@@ -152,6 +155,8 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
filters.add(ImageFilterDualCamera.class);
filters.add(ImageFilterDualCamFusion.class);
filters.add(ImageFilterDualCamSketch.class);
+ filters.add(ImageFilterTruePortrait.class);
+ filters.add(ImageFilterTruePortraitFusion.class);
if(SimpleMakeupImageFilter.HAS_TS_MAKEUP) {
filters.add(ImageFilterMakeupWhiten.class);
@@ -185,6 +190,10 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
return mDualCam;
}
+ public ArrayList<FilterRepresentation> getTruePortrait() {
+ return mTruePortrait;
+ }
+
public ArrayList<FilterRepresentation> getTools() {
return mTools;
}
@@ -462,6 +471,74 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
mDualCam.add(getRepresentation(ImageFilterDualCamFusion.class));
}
+ public void addTruePortrait(Context context) {
+ int[] textId = {
+ R.string.none,
+ R.string.blur,
+ R.string.motion_blur,
+ R.string.halo,
+ R.string.sketch
+ };
+
+ int[] overlayId = {
+ R.drawable.ic_tp_normal,
+ R.drawable.ic_tp_bokeh,
+ R.drawable.ic_tp_motion_blur,
+ R.drawable.ic_tp_halo,
+ R.drawable.ic_tp_sketch
+ };
+
+ String[] serializationNames = {
+ "TRUE_PORTRAIT_NONE",
+ "TRUE_PORTRAIT_BLUR",
+ "TRUE_PORTRAIT_MOTION_BLUR",
+ "TRUE_PORTRAIT_HALO",
+ "TRUE_PORTRAIT_SKETCH"
+ };
+
+ int[][] minMaxValues = {
+ {0,0,0},
+ {0,3,7},
+ {0,3,7},
+ {0,3,7},
+ {0,0,0}
+ };
+
+ boolean[] showParams = {
+ false,
+ true,
+ true,
+ true,
+ false
+ };
+
+ int[] editorIDs = {
+ ImageOnlyEditor.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitImageOnly.ID
+ };
+
+ for (int i = 0; i < textId.length; i++) {
+ FilterRepresentation tPortrait =
+ new FilterBasicRepresentation(context.getString(textId[i]),
+ minMaxValues[i][0], minMaxValues[i][1], minMaxValues[i][2]);
+ tPortrait.setFilterClass(ImageFilterTruePortrait.class);
+ tPortrait.setFilterType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ tPortrait.setTextId(textId[i]);
+ tPortrait.setOverlayId(overlayId[i]);
+ tPortrait.setOverlayOnly(true);
+ tPortrait.setSerializationName(serializationNames[i]);
+ tPortrait.setShowParameterValue(showParams[i]);
+ tPortrait.setEditorId(editorIDs[i]);
+ mTruePortrait.add(tPortrait);
+ addRepresentation(tPortrait);
+ }
+
+ mTruePortrait.add(getRepresentation(ImageFilterTruePortraitFusion.class));
+ }
+
public void removeRepresentation(ArrayList<FilterRepresentation> list,
FilterRepresentation representation) {
for (int i = 0; i < list.size(); i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
index f8d8263d3..8caa9b2b8 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
@@ -40,7 +40,7 @@ import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.editors.EditorDualCamFusion;
-public class FilterDualCamFusionRepresentation extends FilterRepresentation {
+public class FilterDualCamFusionRepresentation extends FilterRepresentation implements FilterFusionRepresentation {
private static final String LOGTAG = "FilterFusionRepresentation";
public static final String SERIALIZATION_NAME = "FUSION";
@@ -112,6 +112,7 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
return mPoint;
}
+ @Override
public void setUnderlay(Uri uri) {
if(uri != null) {
mUri = uri.toString();
@@ -120,6 +121,7 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
}
}
+ @Override
public void setUnderlay(String uri) {
if(uri != null)
mUri = uri;
@@ -127,10 +129,12 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
mUri = "";
}
+ @Override
public boolean hasUnderlay() {
return (mUri != null) && (mUri.isEmpty() == false);
}
+ @Override
public String getUnderlay() {
return mUri;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java
new file mode 100644
index 000000000..ff850c8bc
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.net.Uri;
+
+public interface FilterFusionRepresentation {
+ public void setUnderlay(Uri uri);
+ public void setUnderlay(String uri);
+ public boolean hasUnderlay();
+ public String getUnderlay();
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index 8d1911315..bded1f506 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -50,6 +50,7 @@ public class FilterRepresentation {
public static final byte TYPE_GEOMETRY = 7;
public static final byte TYPE_MAKEUP = 8;
public static final byte TYPE_DUALCAM = 9;
+ public static final byte TYPE_TRUEPORTRAIT = 10;
protected static final String NAME_TAG = "Name";
public FilterRepresentation(String name) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java
new file mode 100644
index 000000000..3864eacfd
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import java.io.IOException;
+
+import android.net.Uri;
+import android.util.JsonReader;
+import android.util.JsonWriter;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+
+
+public class FilterTruePortraitFusionRepresentation extends FilterRepresentation implements FilterFusionRepresentation {
+ private static final String LOGTAG = "FilterTruePortraitFusionRepresentation";
+ public static final String SERIALIZATION_NAME = "TP_FUSION";
+ private static final String SERIAL_UNDERLAY_IMAGE = "image";
+
+ private String mUri = "";
+
+ public FilterTruePortraitFusionRepresentation() {
+ super("Fusion");
+ setSerializationName(SERIALIZATION_NAME);
+ setFilterType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ setFilterClass(ImageFilterTruePortraitFusion.class);
+ setEditorId(EditorTruePortraitFusion.ID);
+ setShowParameterValue(false);
+ setTextId(R.string.fusion);
+ setOverlayId(R.drawable.ic_tp_fusion);
+ setOverlayOnly(true);
+ }
+
+ @Override
+ public FilterRepresentation copy() {
+ FilterTruePortraitFusionRepresentation representation =
+ new FilterTruePortraitFusionRepresentation();
+ copyAllParameters(representation);
+ return representation;
+ }
+
+ @Override
+ protected void copyAllParameters(FilterRepresentation representation) {
+ super.copyAllParameters(representation);
+ representation.useParametersFrom(this);
+ }
+
+ public void useParametersFrom(FilterRepresentation a) {
+ super.useParametersFrom(a);
+ if (a instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation representation = (FilterTruePortraitFusionRepresentation) a;
+ setUnderlay(representation.getUnderlay());
+ }
+ }
+
+ @Override
+ public boolean equals(FilterRepresentation representation) {
+ if (!super.equals(representation)) {
+ return false;
+ }
+ if (representation instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation fusion = (FilterTruePortraitFusionRepresentation) representation;
+ if (fusion.mUri.equals(mUri)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setUnderlay(Uri uri) {
+ if(uri != null) {
+ mUri = uri.toString();
+ } else {
+ mUri = "";
+ }
+ }
+
+ @Override
+ public void setUnderlay(String uri) {
+ if(uri != null)
+ mUri = uri;
+ else
+ mUri = "";
+ }
+
+ @Override
+ public boolean hasUnderlay() {
+ return (mUri != null) && (mUri.isEmpty() == false);
+ }
+
+ @Override
+ public String getUnderlay() {
+ return mUri;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("fusion - underlay: ").append(getUnderlay());
+
+ return sb.toString();
+ }
+
+ // Serialization...
+ public void serializeRepresentation(JsonWriter writer) throws IOException {
+ writer.beginObject();
+ {
+ writer.name(NAME_TAG);
+ writer.value(getName());
+ writer.name(SERIAL_UNDERLAY_IMAGE);
+ writer.value(mUri);
+ }
+ writer.endObject();
+ }
+
+ public void deSerializeRepresentation(JsonReader reader) throws IOException {
+ reader.beginObject();
+ while (reader.hasNext()) {
+ String name = reader.nextName();
+ if (name.equalsIgnoreCase(NAME_TAG)) {
+ setName(reader.nextString());
+ } else if (name.equalsIgnoreCase(SERIAL_UNDERLAY_IMAGE)) {
+ setUnderlay(reader.nextString());
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index 1a32e46e0..4918bee86 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -36,6 +36,8 @@ public abstract class ImageFilter implements Cloneable {
// feedback. Remove this when filters actually work in low memory
// situations.
protected static Activity sActivity = null;
+ private static Toast sToast = null;
+ private String lastMsg;
public static void setActivityForMemoryToasts(Activity activity) {
sActivity = activity;
@@ -43,21 +45,42 @@ public abstract class ImageFilter implements Cloneable {
public static void resetStatics() {
sActivity = null;
+ if (null != sToast) {
+ sToast.cancel();
+ }
+ sToast = null;
}
- public void freeResources() {}
-
- public void displayLowMemoryToast() {
+ void showToast(String msg, int duration) {
if (sActivity != null) {
sActivity.runOnUiThread(new Runnable() {
+ @Override
public void run() {
- Toast.makeText(sActivity, "Memory too low for filter " + getName() +
- ", please file a bug report", Toast.LENGTH_SHORT).show();
+ if (sActivity != null && (!msg.equals(lastMsg) || sToast == null)) {
+ sToast = Toast.makeText(sActivity.getApplicationContext(), msg, duration);
+ lastMsg = msg;
+ }
+ if (sToast != null) {
+ sToast.show();
+ }
}
});
}
}
+ void showToast(int resID, int duration) {
+ if (sActivity != null) {
+ showToast(sActivity.getResources().getString(resID), duration);
+ }
+ }
+
+ public void freeResources() {}
+
+ public void displayLowMemoryToast() {
+ showToast("Memory too low for filter " + getName() +
+ ", please file a bug report", Toast.LENGTH_SHORT);
+ }
+
public void setName(String name) {
mName = name;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java
index 9d9b2b817..df34fedbe 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java
@@ -52,7 +52,6 @@ import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
public class ImageFilterDualCamFusion extends ImageFilter {
private static final String TAG = ImageFilterDualCamFusion.class.getSimpleName();
- private static Toast sSegmentToast;
private FilterDualCamFusionRepresentation mParameters;
private Paint mPaint = new Paint();
@@ -130,15 +129,7 @@ public class ImageFilterDualCamFusion extends ImageFilter {
if(result == false) {
Log.e(TAG, "Imagelib API failed");
- sActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if(sSegmentToast == null) {
- sSegmentToast = Toast.makeText(sActivity, R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
- }
- sSegmentToast.show();
- }
- });
+ showToast(R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
return bitmap;
} else {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java
index 8d61a32c3..97712db75 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java
@@ -51,7 +51,6 @@ import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
public class ImageFilterDualCamSketch extends ImageFilter {
private static final String TAG = ImageFilterDualCamSketch.class.getSimpleName();
- private static Toast sSegmentToast;
private FilterDualCamSketchRepresentation mParameters;
private Paint mPaint = new Paint();
@@ -122,15 +121,7 @@ public class ImageFilterDualCamSketch extends ImageFilter {
if(result == false) {
Log.e(TAG, "Imagelib API failed");
- sActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if(sSegmentToast == null) {
- sSegmentToast = Toast.makeText(sActivity, R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
- }
- sSegmentToast.show();
- }
- });
+ showToast(R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
return bitmap;
} else {
mPaint.reset();
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java
index fa38b0ecb..49728f84c 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java
@@ -51,7 +51,6 @@ import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
public class ImageFilterDualCamera extends ImageFilter {
private static final String TAG = ImageFilterDualCamera.class.getSimpleName();
- private static Toast sSegmentToast;
private FilterDualCamBasicRepresentation mParameters;
private Paint mPaint = new Paint();
@@ -135,16 +134,7 @@ public class ImageFilterDualCamera extends ImageFilter {
if(result == false) {
Log.e(TAG, "Imagelib API failed");
- sActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if(sSegmentToast == null) {
- sSegmentToast = Toast.makeText(sActivity, R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
- }
- sSegmentToast.show();
- }
- });
-
+ showToast(R.string.dualcam_no_segment_toast, Toast.LENGTH_SHORT);
return bitmap;
} else {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
new file mode 100755
index 000000000..f070bfc30
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Log;
+import android.widget.Toast;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.cache.BitmapCache;
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.pipeline.FilterEnvironment;
+import com.android.gallery3d.filtershow.pipeline.ImagePreset;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine.EffectType;
+
+public class ImageFilterTruePortrait extends ImageFilter {
+ private static final String TAG = "ImageFilterTruePortrait";
+
+ private FilterRepresentation mParameters;
+ private Paint mPaint = new Paint();
+
+ public void useRepresentation(FilterRepresentation representation) {
+ mParameters = representation;
+ }
+
+ public FilterRepresentation getParameters() {
+ return mParameters;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
+ if (getParameters() == null) {
+ return bitmap;
+ }
+
+ Bitmap filteredBitmap = null;
+ boolean result = false;
+ int orientation = MasterImage.getImage().getOrientation();
+ Rect originalBounds = MasterImage.getImage().getOriginalBounds();
+ int filteredW;
+ int filteredH;
+
+ if(quality == FilterEnvironment.QUALITY_FINAL) {
+ filteredW = originalBounds.width();
+ filteredH = originalBounds.height();
+ } else {
+ Bitmap originalBmp = MasterImage.getImage().getOriginalBitmapHighres();
+ filteredW = originalBmp.getWidth();
+ filteredH = originalBmp.getHeight();
+
+ // image is rotated
+ if (orientation == ImageLoader.ORI_ROTATE_90 ||
+ orientation == ImageLoader.ORI_ROTATE_270 ||
+ orientation == ImageLoader.ORI_TRANSPOSE ||
+ orientation == ImageLoader.ORI_TRANSVERSE) {
+ int tmp = filteredW;
+ filteredW = filteredH;
+ filteredH = tmp;
+ }
+
+ // non even width or height
+ if(filteredW%2 != 0 || filteredH%2 != 0) {
+ float aspect = (float)filteredH / (float)filteredW;
+ if(filteredW >= filteredH) {
+ filteredW = MasterImage.MAX_BITMAP_DIM;
+ filteredH = (int)(filteredW * aspect);
+ } else {
+ filteredH = MasterImage.MAX_BITMAP_DIM;
+ filteredW = (int)(filteredH / aspect);
+ }
+ }
+ }
+
+ filteredBitmap = MasterImage.getImage().getBitmapCache().getBitmap(filteredW, filteredH, BitmapCache.FILTERS);
+
+ result = applyEffect(filteredBitmap);
+
+ if(result == false) {
+ Log.e(TAG, "Imagelib API failed");
+ showToast("No Faces Found", Toast.LENGTH_SHORT);
+ return bitmap;
+ } else {
+
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ if(quality == FilterEnvironment.QUALITY_FINAL) {
+ mPaint.setFilterBitmap(true);
+ mPaint.setDither(true);
+ }
+
+ if(needsClear()) {
+ bitmap.setHasAlpha(true);
+ bitmap.eraseColor(Color.TRANSPARENT);
+ }
+
+ Canvas canvas = new Canvas(bitmap);
+ ImagePreset preset = getEnvironment().getImagePreset();
+ int bmWidth = bitmap.getWidth();
+ int bmHeight = bitmap.getHeight();
+ GeometryHolder holder;
+ if(preset.getDoApplyGeometry()) {
+ holder = GeometryMathUtils.unpackGeometry(preset.getGeometryFilters());
+ } else {
+ holder = new GeometryHolder();
+ }
+
+ RectF crop = new RectF();
+ Matrix m = GeometryMathUtils.getOriginalToScreen(holder, crop, true,
+ filteredW, filteredH, bmWidth, bmHeight);
+
+ canvas.save();
+ canvas.clipRect(crop);
+ canvas.drawBitmap(filteredBitmap, m, mPaint);
+ canvas.restore();
+
+ MasterImage.getImage().getBitmapCache().cache(filteredBitmap);
+ }
+
+ return bitmap;
+ }
+
+ protected boolean applyEffect(Bitmap filteredBitmap) {
+ FilterBasicRepresentation basicRep = (FilterBasicRepresentation) getParameters();
+ int value = basicRep.getValue();
+
+ boolean result = false;
+ switch(mParameters.getTextId()) {
+ case R.string.blur:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.BLUR, value, filteredBitmap);
+ break;
+ case R.string.motion_blur:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.MOTION_BLUR, value, filteredBitmap);
+ break;
+ case R.string.halo:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.HALO, value, filteredBitmap);
+ break;
+ case R.string.sketch:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.SKETCH, value, filteredBitmap);
+ break;
+ }
+
+ return result;
+ }
+
+ protected boolean needsClear() {
+ return false;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java
new file mode 100644
index 000000000..59a15a325
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+
+public class ImageFilterTruePortraitFusion extends ImageFilterTruePortrait {
+ private static final String TAG = "ImageFilterTruePortraitFusion";
+
+ public ImageFilterTruePortraitFusion() {
+ mName = "Fusion";
+ }
+
+ @Override
+ protected boolean applyEffect(Bitmap filteredBitmap) {
+ filteredBitmap.setHasAlpha(true);
+ return TruePortraitNativeEngine.getInstance().nativeGetForegroundImg(filteredBitmap);
+ }
+
+ @Override
+ protected boolean needsClear() {
+ return true;
+ }
+
+ @Override
+ public FilterRepresentation getDefaultRepresentation() {
+ return new FilterTruePortraitFusionRepresentation();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java
new file mode 100644
index 000000000..88601c4ff
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+
+public class ImageFilterTruePortraitMask extends ImageFilter {
+ private static final String TAG = "ImageFilterTruePortraitMask";
+
+ private FilterBasicRepresentation mParameters;
+
+ public void useRepresentation(FilterRepresentation representation) {
+ FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation;
+ mParameters = parameters;
+ }
+
+ public FilterBasicRepresentation getParameters() {
+ return mParameters;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/SeeStraightActs.java b/src/com/android/gallery3d/filtershow/filters/SeeStraightActs.java
index 047c036f7..f2eb81bc5 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/SeeStraightActs.java
+++ b/src/com/android/gallery3d/filtershow/filters/SeeStraightActs.java
@@ -100,22 +100,14 @@ public class SeeStraightActs extends SimpleImageFilter {
return bitmap;
if(!checkSize(width, height)) {
- sActivity.runOnUiThread(new Runnable() {
- public void run() {
- Toast.makeText(sActivity, sActivity.getResources().getString(R.string.seestraight_input_image_is_small), Toast.LENGTH_SHORT).show();
- }
- });
+ showToast(R.string.seestraight_input_image_is_small, Toast.LENGTH_SHORT);
return bitmap;
}
Bitmap dstBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] outputRoi = processImage(width, height, bitmap, dstBitmap);
if(outputRoi == null) {
- sActivity.runOnUiThread(new Runnable() {
- public void run() {
- Toast.makeText(sActivity, sActivity.getResources().getString(R.string.seestraight_process_fail), Toast.LENGTH_SHORT).show();
- }
- });
+ showToast(R.string.seestraight_process_fail, Toast.LENGTH_SHORT);
return bitmap;
}
dstBitmap = Bitmap.createBitmap(dstBitmap, outputRoi[0], outputRoi[1], outputRoi[2], outputRoi[3]);
diff --git a/src/com/android/gallery3d/filtershow/filters/TrueScannerActs.java b/src/com/android/gallery3d/filtershow/filters/TrueScannerActs.java
index da6e538ab..0a59a65c5 100644..100755
--- a/src/com/android/gallery3d/filtershow/filters/TrueScannerActs.java
+++ b/src/com/android/gallery3d/filtershow/filters/TrueScannerActs.java
@@ -103,23 +103,27 @@ public class TrueScannerActs extends SimpleImageFilter {
}
private void showProgressDialog() {
- sActivity.runOnUiThread(new Runnable() {
- public void run() {
- mProgressDialog = ProgressDialog.show(sActivity,"", "Processing...", true, false);
- mProgressDialog.show();
- }
- });
+ if (null != sActivity) {
+ sActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mProgressDialog = ProgressDialog.show(sActivity, "", "Processing...", true, false);
+ mProgressDialog.show();
+ }
+ });
+ }
}
private void dismissProgressDialog() {
- sActivity.runOnUiThread(new Runnable() {
- public void run() {
- if (mProgressDialog != null && mProgressDialog.isShowing()) {
- mProgressDialog.dismiss();
- mProgressDialog = null;
+ if (null != sActivity) {
+ sActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ if (mProgressDialog != null && mProgressDialog.isShowing()) {
+ mProgressDialog.dismiss();
+ mProgressDialog = null;
+ }
}
- }
- });
+ });
+ }
}
@Override
@@ -132,13 +136,7 @@ public class TrueScannerActs extends SimpleImageFilter {
return bitmap;
}
if(!acquireLock(true)) {
- sActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(sActivity, "Still processing the previous request... ", Toast.LENGTH_LONG).show();
- }
- });
-
+ showToast("Still processing the previous request... ", Toast.LENGTH_LONG);
return bitmap;
}
new Throwable().printStackTrace();
diff --git a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
index c3a517c66..764312199 100644..100755
--- a/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/GeometryMathUtils.java
@@ -484,6 +484,32 @@ public final class GeometryMathUtils {
return m;
}
+ public static Matrix getSegMatrix(GeometryHolder holder, int bitmapWidth,
+ int bitmapHeight, int viewWidth, int viewHeight
+ , int oldw, int oldh) {
+ int bh = bitmapHeight;
+ int bw = bitmapWidth;
+ if (GeometryMathUtils.needsDimensionSwap(holder.rotation)) {
+ bh = bitmapWidth;
+ bw = bitmapHeight;
+ }
+ float oldScale = GeometryMathUtils.scale(bw, bh, oldw, oldh);
+ if (oldScale > 3.0f) {
+ oldScale = 3.0f;
+ }
+ oldScale *= SHOW_SCALE;
+ float scale = GeometryMathUtils.scale(bw, bh, viewWidth, viewHeight);
+ if (scale > 3.0f) {
+ scale = 3.0f;
+ }
+ scale *= SHOW_SCALE;
+ Matrix m = new Matrix();
+ m.setTranslate(-oldw / 2f, -oldh / 2f);
+ m.postScale(scale / oldScale, scale / oldScale);
+ m.postTranslate(viewWidth / 2f, viewHeight / 2f);
+ return m;
+ }
+
public static RectF getTrueCropRect(GeometryHolder holder, int bitmapWidth, int bitmapHeight) {
RectF r = new RectF(holder.crop);
FilterCropRepresentation.findScaledCrop(r, bitmapWidth, bitmapHeight);
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index c3a7b7f38..7926d6fa6 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -66,8 +66,8 @@ public class ImageShow extends View implements OnGestureListener,
protected int mBackgroundColor;
- private GestureDetector mGestureDetector = null;
- private ScaleGestureDetector mScaleGestureDetector = null;
+ protected GestureDetector mGestureDetector = null;
+ protected ScaleGestureDetector mScaleGestureDetector = null;
private RectF mFusionBounds = new RectF();
protected Rect mImageBounds = new Rect();
@@ -78,32 +78,32 @@ public class ImageShow extends View implements OnGestureListener,
private int mShadowMargin = 15; // not scaled, fixed in the asset
private boolean mShadowDrawn = false;
- private Point mTouchDown = new Point();
- private Point mTouch = new Point();
- private boolean mFinishedScalingOperation = false;
+ protected Point mTouchDown = new Point();
+ protected Point mTouch = new Point();
+ protected boolean mFinishedScalingOperation = false;
private boolean mZoomIn = false;
Point mOriginalTranslation = new Point();
float mOriginalScale;
float mStartFocusX, mStartFocusY;
- private EdgeEffectCompat mEdgeEffect = null;
- private static final int EDGE_LEFT = 1;
- private static final int EDGE_TOP = 2;
- private static final int EDGE_RIGHT = 3;
- private static final int EDGE_BOTTOM = 4;
- private int mCurrentEdgeEffect = 0;
- private int mEdgeSize = 100;
+ protected EdgeEffectCompat mEdgeEffect = null;
+ protected static final int EDGE_LEFT = 1;
+ protected static final int EDGE_TOP = 2;
+ protected static final int EDGE_RIGHT = 3;
+ protected static final int EDGE_BOTTOM = 4;
+ protected int mCurrentEdgeEffect = 0;
+ protected int mEdgeSize = 100;
- private static final int mAnimationSnapDelay = 200;
- private static final int mAnimationZoomDelay = 400;
- private ValueAnimator mAnimatorScale = null;
- private ValueAnimator mAnimatorTranslateX = null;
- private ValueAnimator mAnimatorTranslateY = null;
+ protected static final int mAnimationSnapDelay = 200;
+ protected static final int mAnimationZoomDelay = 400;
+ protected ValueAnimator mAnimatorScale = null;
+ protected ValueAnimator mAnimatorTranslateX = null;
+ protected ValueAnimator mAnimatorTranslateY = null;
protected boolean mAllowScaleAndTranslate = false;
- private enum InteractionMode {
+ protected enum InteractionMode {
NONE,
SCALE,
MOVE
@@ -298,16 +298,7 @@ public class ImageShow extends View implements OnGestureListener,
mShadowDrawn = false;
if (!drawCompareImage(canvas, MasterImage.getImage().getOriginalBitmapLarge())) {
- Bitmap highresPreview = MasterImage.getImage().getHighresImage();
- Bitmap fullHighres = MasterImage.getImage().getPartialImage();
-
- boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation();
-
- if (highresPreview == null || isDoingNewLookAnimation) {
- drawImageAndAnimate(canvas, getFilteredImage());
- } else {
- drawImageAndAnimate(canvas, highresPreview);
- }
+ drawImageAndAnimate(canvas, getImageToDraw());
}
canvas.restore();
@@ -337,6 +328,17 @@ public class ImageShow extends View implements OnGestureListener,
}
}
+ protected Bitmap getImageToDraw() {
+ Bitmap highresPreview = MasterImage.getImage().getHighresImage();
+ boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation();
+
+ if (highresPreview == null || isDoingNewLookAnimation) {
+ return getFilteredImage();
+ } else {
+ return highresPreview;
+ }
+ }
+
private void drawHighresImage(Canvas canvas, Bitmap fullHighres) {
Matrix originalToScreen = MasterImage.getImage().originalImageToScreen();
if (fullHighres != null && originalToScreen != null) {
@@ -774,7 +776,7 @@ public class ImageShow extends View implements OnGestureListener,
return true;
}
- private void constrainTranslation(Point translation, float scale) {
+ protected void constrainTranslation(Point translation, float scale) {
int currentEdgeEffect = 0;
if (mAllowScaleAndTranslate || scale <= 1) {
mCurrentEdgeEffect = 0;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java
new file mode 100644
index 000000000..8413c5dd9
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.util.AttributeSet;
+
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
+
+public class ImageTruePortraitFusion extends ImageShow {
+ private static final String LOGTAG = "ImageTruePortraitFusion";
+ protected EditorTruePortraitFusion mEditor;
+ protected FilterTruePortraitFusionRepresentation mRepresentation;
+ private Bitmap mUnderlay;
+
+ public ImageTruePortraitFusion(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAllowScaleAndTranslate = true;
+ }
+
+ public ImageTruePortraitFusion(Context context) {
+ super(context);
+ mAllowScaleAndTranslate = true;
+ }
+
+ public void setUnderlay(Uri uri) {
+ mRepresentation.setUnderlay(uri);
+
+ if(mUnderlay != null) {
+ mUnderlay.recycle();
+ mUnderlay = null;
+ MasterImage.getImage().setFusionUnderlay(null);
+ }
+
+ mUnderlay = ImageLoader.loadConstrainedBitmap(uri, getContext(), MasterImage.MAX_BITMAP_DIM, new Rect(), false);
+ MasterImage.getImage().setFusionUnderlay(mUnderlay);
+ invalidate();
+ }
+
+ public void setEditor(EditorTruePortraitFusion editor) {
+ mEditor = editor;
+ }
+
+ public void setRepresentation(FilterTruePortraitFusionRepresentation representation) {
+ mRepresentation = representation;
+ }
+
+ @Override
+ public boolean enableComparison() {
+ return false;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java
new file mode 100644
index 000000000..052035714
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.imageshow;
+
+import java.util.Arrays;
+import java.util.Stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.LightingColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
+import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+
+public class ImageTruePortraitMask extends ImageShow {
+
+ private static final String LOGTAG = "ImageTruePortraitMask";
+
+ private boolean mZoomIn = false;
+ private Point mScaleTranslation = new Point();
+ private float mScaleStartFocusX, mScaleStartFocusY;
+
+ private Point mTranslation = new Point();
+ private Point mOriginalTranslation = new Point();
+ private float mScaleFactor = 1f;
+ private float mMaxScaleFactor = 3f;
+
+ private Paint mMaskPaintForeground = new Paint();
+ private Paint mMaskPaintBackground = new Paint();
+ private Paint mMaskEditPaint = new Paint();
+
+ private StrokeData mCurrent;
+ private Stack<StrokeData> mDrawing = new Stack<StrokeData>();
+
+ private EditorTruePortraitMask mEditor;
+ private Bitmap mPreview;
+ private Bitmap mOriginalMask;
+ private Bitmap mMask;
+
+ private Mode mMode = Mode.MODE_NONE;
+ private enum Mode {
+ MODE_NONE,
+ MODE_MOVE,
+ MODE_SCALE,
+ MODE_DRAW
+ }
+
+ public ImageTruePortraitMask(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setup();
+ }
+
+ public ImageTruePortraitMask(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public ImageTruePortraitMask(Context context) {
+ super(context);
+ setup();
+ }
+
+ private void setup() {
+ mMaskPaintForeground.setAntiAlias(true);
+ mMaskPaintForeground.setColor(Color.RED);
+ mMaskPaintForeground.setColorFilter(new LightingColorFilter(Color.RED, 1));
+ mMaskPaintForeground.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
+
+ mMaskPaintBackground.setAntiAlias(true);
+ mMaskPaintBackground.setColor(Color.GREEN);
+ mMaskPaintBackground.setColorFilter(new ColorMatrixColorFilter(new float[] {
+ // Set color to GREEN and inverse ALPHA channel
+ // of original mask to get background
+ 0,0,0,0,0,
+ 0,0,0,0,255,
+ 0,0,0,0,0,
+ 0,0,0,-1,255
+ }));
+ mMaskPaintBackground.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
+
+ mMaskEditPaint.setAntiAlias(true);
+ mMaskEditPaint.setStyle(Style.STROKE);
+ mMaskEditPaint.setStrokeCap(Paint.Cap.ROUND);
+ }
+
+ @Override
+ public void attach() {
+ mPreview = TruePortraitNativeEngine.getInstance().getPreview();
+ mOriginalMask = TruePortraitNativeEngine.getInstance().getMask();
+ mMask = Bitmap.createBitmap(mOriginalMask.getWidth(), mOriginalMask.getHeight(), mOriginalMask.getConfig());
+ }
+
+ @Override
+ public void detach() {
+ if(mPreview != null) {
+ mPreview.recycle();
+ mPreview = null;
+ }
+
+ if(mOriginalMask != null) {
+ mOriginalMask.recycle();
+ mOriginalMask = null;
+ }
+
+ if(mMask != null) {
+ mMask.recycle();
+ mMask = null;
+ }
+
+ mDrawing.clear();
+ }
+
+ public void setEditor(EditorTruePortraitMask editor) {
+ mEditor = editor;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ toggleComparisonButtonVisibility();
+
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ mPaint.setFilterBitmap(true);
+
+ drawImage(canvas, mPreview, mPaint);
+ updateEditsToMask(mMask);
+ drawImage(canvas, mMask,
+ mEditor.isBackgroundMode()?mMaskPaintBackground:mMaskPaintForeground);
+
+ if (!mEdgeEffect.isFinished()) {
+ canvas.save();
+ float dx = (getHeight() - getWidth()) / 2f;
+ if (getWidth() > getHeight()) {
+ dx = - (getWidth() - getHeight()) / 2f;
+ }
+ if (mCurrentEdgeEffect == EDGE_BOTTOM) {
+ canvas.rotate(180, getWidth()/2, getHeight()/2);
+ } else if (mCurrentEdgeEffect == EDGE_RIGHT) {
+ canvas.rotate(90, getWidth()/2, getHeight()/2);
+ canvas.translate(0, dx);
+ } else if (mCurrentEdgeEffect == EDGE_LEFT) {
+ canvas.rotate(270, getWidth()/2, getHeight()/2);
+ canvas.translate(0, dx);
+ }
+ if (mCurrentEdgeEffect != 0) {
+ mEdgeEffect.draw(canvas);
+ }
+ canvas.restore();
+ invalidate();
+ } else {
+ mCurrentEdgeEffect = 0;
+ }
+ }
+
+ private void drawImage(Canvas canvas, Bitmap image, Paint paint) {
+ if (image == null) {
+ return;
+ }
+
+ Matrix m = computeImageToScreen(image.getWidth(), image.getHeight());
+ if (m == null) {
+ return;
+ }
+
+ canvas.save();
+ image.setHasAlpha(true);
+ canvas.drawBitmap(image, m, paint);
+ canvas.restore();
+ }
+
+ private void updateEditsToMask(Bitmap mask) {
+ // clear mask and reset with original
+ mask.eraseColor(Color.TRANSPARENT);
+ Canvas canvas = new Canvas(mask);
+ canvas.drawBitmap(mOriginalMask, 0, 0, null);
+
+ for(StrokeData sd:mDrawing) {
+ drawEdit(canvas, sd);
+ }
+
+ // update current edit
+ if(mCurrent != null) {
+ drawEdit(canvas, mCurrent);
+ }
+ }
+
+ private void drawEdit(Canvas canvas, StrokeData sd) {
+ if (sd == null) {
+ return;
+ }
+ if (sd.mPath == null) {
+ return;
+ }
+ mMaskEditPaint.setColor(sd.mColor);
+ if(sd.mColor == Color.TRANSPARENT)
+ mMaskEditPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ else
+ mMaskEditPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ mMaskEditPaint.setStrokeWidth(sd.mRadius);
+
+ canvas.drawPath(sd.mPath, mMaskEditPaint);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int action = event.getAction();
+ action = action & MotionEvent.ACTION_MASK;
+
+ boolean scaleInProgress = scaleInProgress();
+ mGestureDetector.onTouchEvent(event);
+ mScaleGestureDetector.onTouchEvent(event);
+
+ if (mMode == Mode.MODE_SCALE) {
+ return true;
+ }
+ if (!scaleInProgress() && scaleInProgress) {
+ // If we were scaling, the scale will stop but we will
+ // still issue an ACTION_UP. Let the subclasses know.
+ mFinishedScalingOperation = true;
+ }
+
+ int ex = (int) event.getX();
+ int ey = (int) event.getY();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mTouchDown.x = ex;
+ mTouchDown.y = ey;
+ if(event.getPointerCount() == 2) {
+ mMode = Mode.MODE_MOVE;
+ setOriginalTranslation(getTranslation());
+ } else if (event.getPointerCount() == 1) {
+ mMode = Mode.MODE_DRAW;
+ Point mapPoint = mapPoint(ex, ey);
+ startNewSection(mapPoint.x, mapPoint.y);
+ }
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ mTouch.x = ex;
+ mTouch.y = ey;
+
+ float scaleFactor = getScaleFactor();
+ if (scaleFactor > 1 && event.getPointerCount() == 2
+ && mMode == Mode.MODE_MOVE) {
+ float translateX = (mTouch.x - mTouchDown.x) / scaleFactor;
+ float translateY = (mTouch.y - mTouchDown.y) / scaleFactor;
+ Point originalTranslation = getOriginalTranslation();
+ Point translation = getTranslation();
+ translation.x = (int) (originalTranslation.x + translateX);
+ translation.y = (int) (originalTranslation.y + translateY);
+ setTranslation(translation);
+ } else if(event.getPointerCount() == 1
+ && mMode == Mode.MODE_DRAW) {
+ Point mapPoint = mapPoint(ex, ey);
+ addPoint(mapPoint.x, mapPoint.y);
+ }
+ } else if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_CANCEL
+ || action == MotionEvent.ACTION_OUTSIDE) {
+ if(event.getPointerCount() == 1
+ && mMode == Mode.MODE_DRAW) {
+ Point mapPoint = mapPoint(ex, ey);
+ endSection(mapPoint.x, mapPoint.y);
+ }
+
+ mMode = Mode.MODE_NONE;
+ mTouchDown.x = 0;
+ mTouchDown.y = 0;
+ mTouch.x = 0;
+ mTouch.y = 0;
+ if (getScaleFactor() <= 1) {
+ setScaleFactor(1);
+ setTranslation(new Point(0,0));
+ }
+ }
+
+ float scaleFactor = getScaleFactor();
+ Point translation = getTranslation();
+ constrainTranslation(translation, scaleFactor);
+ setTranslation(translation);
+
+ invalidate();
+ return true;
+ }
+
+ private void startAnimTranslation(int fromX, int toX,
+ int fromY, int toY, int delay) {
+ if (fromX == toX && fromY == toY) {
+ return;
+ }
+ if (mAnimatorTranslateX != null) {
+ mAnimatorTranslateX.cancel();
+ }
+ if (mAnimatorTranslateY != null) {
+ mAnimatorTranslateY.cancel();
+ }
+ mAnimatorTranslateX = ValueAnimator.ofInt(fromX, toX);
+ mAnimatorTranslateY = ValueAnimator.ofInt(fromY, toY);
+ mAnimatorTranslateX.setDuration(delay);
+ mAnimatorTranslateY.setDuration(delay);
+ mAnimatorTranslateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ Point translation = getTranslation();
+ translation.x = (Integer) animation.getAnimatedValue();
+ setTranslation(translation);
+ invalidate();
+ }
+ });
+ mAnimatorTranslateY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ Point translation = getTranslation();
+ translation.y = (Integer) animation.getAnimatedValue();
+ setTranslation(translation);
+ invalidate();
+ }
+ });
+ mAnimatorTranslateX.start();
+ mAnimatorTranslateY.start();
+ }
+
+ private void applyTranslationConstraints() {
+ float scaleFactor = getScaleFactor();
+ Point translation = getTranslation();
+ int x = translation.x;
+ int y = translation.y;
+ constrainTranslation(translation, scaleFactor);
+
+ if (x != translation.x || y != translation.y) {
+ startAnimTranslation(x, translation.x,
+ y, translation.y,
+ mAnimationSnapDelay);
+ }
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent arg0) {
+ if(hasFusionApplied())
+ return true;
+
+ mZoomIn = !mZoomIn;
+ float scale = 1.0f;
+ final float x = arg0.getX();
+ final float y = arg0.getY();
+ if (mZoomIn) {
+ scale = getMaxScaleFactor();
+ }
+ if (scale != getScaleFactor()) {
+ if (mAnimatorScale != null) {
+ mAnimatorScale.cancel();
+ }
+ mAnimatorScale = ValueAnimator.ofFloat(
+ getScaleFactor(),
+ scale
+ );
+ float translateX = (getWidth() / 2 - x);
+ float translateY = (getHeight() / 2 - y);
+ Point translation = getTranslation();
+ int startTranslateX = translation.x;
+ int startTranslateY = translation.y;
+ if (scale != 1.0f) {
+ translation.x = (int) (mScaleTranslation.x + translateX);
+ translation.y = (int) (mScaleTranslation.y + translateY);
+ } else {
+ translation.x = 0;
+ translation.y = 0;
+ }
+ constrainTranslation(translation, scale);
+
+ startAnimTranslation(startTranslateX, translation.x,
+ startTranslateY, translation.y,
+ mAnimationZoomDelay);
+ mAnimatorScale.setDuration(mAnimationZoomDelay);
+ mAnimatorScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setScaleFactor((Float) animation.getAnimatedValue());
+ invalidate();
+ }
+ });
+ mAnimatorScale.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ applyTranslationConstraints();
+ invalidate();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ });
+ mAnimatorScale.start();
+ }
+ return true;
+ }
+
+ protected void constrainTranslation(Point translation, float scale) {
+ int currentEdgeEffect = 0;
+ if (mAllowScaleAndTranslate || scale <= 1) {
+ mCurrentEdgeEffect = 0;
+ mEdgeEffect.finish();
+ return;
+ }
+
+ Rect originalBounds = MasterImage.getImage().getOriginalBounds();
+ Matrix originalToScreen = computeImageToScreen(originalBounds.width(), originalBounds.height());
+ RectF screenPos = new RectF(originalBounds);
+ originalToScreen.mapRect(screenPos);
+
+ boolean rightConstraint = screenPos.right < getWidth();
+ boolean leftConstraint = screenPos.left > 0;
+ boolean topConstraint = screenPos.top > 0;
+ boolean bottomConstraint = screenPos.bottom < getHeight();
+
+ if (screenPos.width() > getWidth()) {
+ if (rightConstraint && !leftConstraint) {
+ float tx = screenPos.right - translation.x * scale;
+ translation.x = (int) ((getWidth() - tx) / scale);
+ currentEdgeEffect = EDGE_RIGHT;
+ } else if (leftConstraint && !rightConstraint) {
+ float tx = screenPos.left - translation.x * scale;
+ translation.x = (int) ((-tx) / scale);
+ currentEdgeEffect = EDGE_LEFT;
+ }
+ } else {
+ float tx = screenPos.right - translation.x * scale;
+ float dx = (getWidth() - screenPos.width()) / 2f;
+ translation.x = (int) ((getWidth() - tx - dx) / scale);
+ }
+
+ if (screenPos.height() > getHeight()) {
+ if (bottomConstraint && !topConstraint) {
+ float ty = screenPos.bottom - translation.y * scale;
+ translation.y = (int) ((getHeight() - ty) / scale);
+ currentEdgeEffect = EDGE_BOTTOM;
+ } else if (topConstraint && !bottomConstraint) {
+ float ty = screenPos.top - translation.y * scale;
+ translation.y = (int) ((-ty) / scale);
+ currentEdgeEffect = EDGE_TOP;
+ }
+ } else {
+ float ty = screenPos.bottom - translation.y * scale;
+ float dy = (getHeight()- screenPos.height()) / 2f;
+ translation.y = (int) ((getHeight() - ty - dy) / scale);
+ }
+
+ if (mCurrentEdgeEffect != currentEdgeEffect) {
+ if (mCurrentEdgeEffect == 0 || currentEdgeEffect != 0) {
+ mCurrentEdgeEffect = currentEdgeEffect;
+ mEdgeEffect.finish();
+ }
+ mEdgeEffect.setSize(getWidth(), mEdgeSize);
+ }
+ if (currentEdgeEffect != 0) {
+ mEdgeEffect.onPull(mEdgeSize);
+ }
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ float scaleFactor = getScaleFactor();
+
+ scaleFactor = scaleFactor * detector.getScaleFactor();
+ if (scaleFactor > getMaxScaleFactor()) {
+ scaleFactor = getMaxScaleFactor();
+ }
+
+ if (scaleFactor < 1.0f) {
+ scaleFactor = 1.0f;
+ }
+
+ setScaleFactor(scaleFactor);
+ float focusx = detector.getFocusX();
+ float focusy = detector.getFocusY();
+ float translateX = (focusx - mScaleStartFocusX) / scaleFactor;
+ float translateY = (focusy - mScaleStartFocusY) / scaleFactor;
+ Point translation = getTranslation();
+ translation.x = (int) (mScaleTranslation.x + translateX);
+ translation.y = (int) (mScaleTranslation.y + translateY);
+ setTranslation(translation);
+ invalidate();
+ return true;
+ }
+
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ Point pos = getTranslation();
+ mScaleTranslation.x = pos.x;
+ mScaleTranslation.y = pos.y;
+ mScaleStartFocusX = detector.getFocusX();
+ mScaleStartFocusY = detector.getFocusY();
+ mMode = Mode.MODE_SCALE;
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ mMode = Mode.MODE_NONE;
+ if (getScaleFactor() < 1) {
+ setScaleFactor(1);
+ invalidate();
+ }
+ }
+
+ @Override
+ public boolean hasFusionApplied() {
+ return false;
+ }
+
+ private Matrix computeImageToScreen(int bmWidth, int bmHeight) {
+ float scale = 1f;
+ float translateX = 0;
+ float translateY = 0;
+
+ RectF size = new RectF(0, 0,
+ bmWidth, bmHeight);
+ float scaleW = getWidth() / size.width();
+ float scaleH = getHeight() / size.height();
+ scale = Math.min(scaleW, scaleH);
+ translateX = (getWidth() - (size.width() * scale)) / 2.0f;
+ translateY = (getHeight() - (size.height() * scale)) / 2.0f;
+
+ Point translation = getTranslation();
+ Matrix m = new Matrix();
+ m.postScale(scale, scale);
+ m.postTranslate(translateX, translateY);
+ m.postScale(getScaleFactor(), getScaleFactor(),
+ getWidth() / 2.0f,
+ getHeight() / 2.0f);
+ m.postTranslate(translation.x * getScaleFactor(),
+ translation.y * getScaleFactor());
+ return m;
+ }
+
+ private Matrix computeScreenToImage(int bmWidth, int bmHeight) {
+ Matrix m = computeImageToScreen(bmWidth, bmHeight);
+ Matrix inverse = new Matrix();
+ m.invert(inverse);
+ return inverse;
+ }
+
+ private Point mapPoint(int x, int y) {
+ Matrix screenToImage = computeScreenToImage(mMask.getWidth(), mMask.getHeight());
+ float[] tmpPoint = {x,y};
+ screenToImage.mapPoints(tmpPoint);
+
+ return new Point((int)tmpPoint[0], (int)tmpPoint[1]);
+ }
+
+ private void setTranslation(Point translation) {
+ mTranslation.x = translation.x;
+ mTranslation.y = translation.y;
+ }
+
+ private void setOriginalTranslation(Point translation) {
+ mOriginalTranslation.x = translation.x;
+ mOriginalTranslation.y = translation.y;
+ }
+
+ private void setScaleFactor(float scale) {
+ mScaleFactor = scale;
+ }
+
+ private Point getTranslation() {
+ return mTranslation;
+ }
+
+ private Point getOriginalTranslation() {
+ return mOriginalTranslation;
+ }
+
+ private float getScaleFactor() {
+ return mScaleFactor;
+ }
+
+ private float getMaxScaleFactor() {
+ return mMaxScaleFactor;
+ }
+
+ private void fillStrokeParameters(StrokeData sd){
+ sd.mColor = mEditor.isBackgroundMode()?Color.TRANSPARENT:Color.BLACK;
+ sd.mRadius = mEditor.getBrushSize();
+ }
+
+ private void startNewSection(float x, float y) {
+ mCurrent = new StrokeData();
+ fillStrokeParameters(mCurrent);
+ mCurrent.mPath = new Path();
+ mCurrent.mPath.moveTo(x, y);
+ mCurrent.mPoints[0] = x;
+ mCurrent.mPoints[1] = y;
+ mCurrent.noPoints = 1;
+ }
+
+ private void addPoint(float x, float y) {
+ int len = mCurrent.noPoints * 2;
+ mCurrent.mPath.lineTo(x, y);
+ if ((len+2) > mCurrent.mPoints.length) {
+ mCurrent.mPoints = Arrays.copyOf(mCurrent.mPoints, mCurrent.mPoints.length * 2);
+ }
+ mCurrent.mPoints[len] = x;
+ mCurrent.mPoints[len + 1] = y;
+ mCurrent.noPoints++;
+ }
+
+ private void endSection(float x, float y) {
+ addPoint(x, y);
+ mDrawing.push(mCurrent);
+ mCurrent = null;
+ mEditor.refreshUndoButton();
+ }
+
+ private void resetDrawing() {
+ mCurrent = null;
+ }
+
+ public boolean canUndoEdit() {
+ return !mDrawing.isEmpty();
+ }
+
+ public void undoLastEdit() {
+ if(!mDrawing.isEmpty()) {
+ mDrawing.pop();
+ mEditor.refreshUndoButton();
+ invalidate();
+ }
+ }
+
+ public void applyMaskUpdates() {
+ TruePortraitNativeEngine.getInstance().updateMask(mDrawing);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTrueScanner.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTrueScanner.java
index 9d8e36d07..d72ec3783 100644..100755
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageTrueScanner.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTrueScanner.java
@@ -58,7 +58,7 @@ public class ImageTrueScanner extends ImageShow {
private Matrix mDisplayMatrix;
private GeometryMathUtils.GeometryHolder mGeometry;
public final static int POINT_NUMS = 4;
- private static int[] mSegPoints = new int[POINT_NUMS*2+4];
+ private static float[] mSegPoints = new float[POINT_NUMS*2+4];
private boolean[] isTouched = new boolean[POINT_NUMS];
private RectF mBitmapBound = new RectF();
private Bitmap mBitmap;
@@ -77,6 +77,9 @@ public class ImageTrueScanner extends ImageShow {
private Paint mGrayPaint;
private Bitmap mGlareButtonOnBitmap;
private Bitmap mGlareButtonOffBitmap;
+ private boolean updateGlareRemovalButton = false;
+ private Matrix mDisplaySegPointsMatrix;
+ private Matrix mDisplayMatrixInverse;
public ImageTrueScanner(Context context) {
super(context);
@@ -94,7 +97,11 @@ public class ImageTrueScanner extends ImageShow {
}
public static int[] getDeterminedPoints() {
- return mSegPoints;
+ int[] points = new int[mSegPoints.length];
+ for (int i = 0; i < mSegPoints.length; i++) {
+ points[i] = (int)mSegPoints[i];
+ }
+ return points;
}
public static boolean getRemoveGlareButtonStatus() {
@@ -219,6 +226,28 @@ public class ImageTrueScanner extends ImageShow {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
+ updateMatrix(w,h,oldw, oldh);
+ mDisplaySegPointsMatrix.mapPoints(mSegPoints);
+ getBitmapBound();
+ updateGlareRemovalButton = true;
+ }
+
+ private void updateMatrix(int w, int h, int oldw, int oldh) {
+ if (mBitmap == null) {
+ return;
+ }
+ Resources res = getContext().getResources();
+ int panelHeight = res.getDimensionPixelOffset(R.dimen.category_actionbar_panel_height);
+ mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
+ mBitmap.getWidth(), mBitmap.getHeight(), w, h - panelHeight);
+ mDisplaySegPointsMatrix = GeometryMathUtils.getSegMatrix(mGeometry, mBitmap.getWidth(),
+ mBitmap.getHeight(), w, h - panelHeight, oldw, oldh- panelHeight);
+ mDisplayMatrixInverse = new Matrix();
+ mDisplayMatrixInverse.reset();
+ if (!mDisplaySegPointsMatrix.invert(mDisplayMatrixInverse)) {
+ Log.w(TAG, "could not invert display matrix");
+ mDisplayMatrixInverse = null;
+ }
}
private void getBitmapBound() {
@@ -283,9 +312,20 @@ public class ImageTrueScanner extends ImageShow {
return;
toggleComparisonButtonVisibility();
- if(mDisplayMatrix == null) {
+ if(mDisplayMatrix == null || mDisplaySegPointsMatrix == null
+ || mDisplayMatrixInverse == null) {
mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
mBitmap.getWidth(), mBitmap.getHeight(), canvas.getWidth(), canvas.getHeight());
+ mDisplaySegPointsMatrix = GeometryMathUtils.getSegMatrix(mGeometry,
+ mBitmap.getWidth(), mBitmap.getHeight(), canvas.getWidth(),
+ canvas.getHeight(),canvas.getWidth(), canvas.getHeight());
+ mDisplayMatrixInverse = new Matrix();
+ mDisplayMatrixInverse.reset();
+ if (!mDisplaySegPointsMatrix.invert(mDisplayMatrixInverse)) {
+ Log.w(TAG, "could not invert display matrix");
+ mDisplayMatrixInverse = null;
+ return;
+ }
getBitmapBound();
}
if(!isDetectedPointsApplied) {
@@ -308,9 +348,10 @@ public class ImageTrueScanner extends ImageShow {
}
private void drawGlareRemovalButton(Canvas canvas) {
- if(mGlareButtonX == -1000 && mGlareButtonY == -1000) {
+ if(mGlareButtonX == -1000 && mGlareButtonY == -1000 || updateGlareRemovalButton) {
mGlareButtonX = canvas.getWidth()/2;
mGlareButtonY = canvas.getHeight()*1/5;
+ updateGlareRemovalButton = false;
}
RectF rectF = new RectF();
Bitmap bitmap;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index b2aae85a6..0a13da737 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -40,6 +40,7 @@ import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentatio
import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.history.HistoryItem;
@@ -53,7 +54,6 @@ import com.android.gallery3d.filtershow.pipeline.SharedPreset;
import com.android.gallery3d.filtershow.state.StateAdapter;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine.DdmStatus;
-import com.android.gallery3d.mpo.MpoParser;
public class MasterImage implements RenderingRequestCaller {
@@ -272,6 +272,24 @@ public class MasterImage implements RenderingRequestCaller {
}
};
+ 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 @@ public class MasterImage implements RenderingRequestCaller {
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;
@@ -417,9 +443,12 @@ public class MasterImage implements RenderingRequestCaller {
}
public synchronized boolean hasFusionApplied() {
- FilterRepresentation representation =
+ FilterRepresentation dcRepresentation =
mPreset.getFilterWithSerializationName(FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
- if(representation instanceof FilterDualCamFusionRepresentation) {
+ FilterRepresentation tpRepresentation =
+ mPreset.getFilterWithSerializationName(FilterTruePortraitFusionRepresentation.SERIALIZATION_NAME);
+ if(dcRepresentation instanceof FilterDualCamFusionRepresentation ||
+ tpRepresentation instanceof FilterTruePortraitFusionRepresentation) {
return true;
}
return false;
@@ -931,11 +960,11 @@ public class MasterImage implements RenderingRequestCaller {
return mPreset.contains(FilterRepresentation.TYPE_TINYPLANET);
}
- public boolean loadMpo(byte[] auxiliaryMpoData) {
+ public boolean loadMpo(byte[] primaryMpoData, byte[] auxiliaryMpoData) {
boolean loaded = false;
if(auxiliaryMpoData != null) {
- Bitmap primaryBm = ImageLoader.loadBitmap(getActivity(), getUri(), null);
+ Bitmap primaryBm = BitmapFactory.decodeByteArray(primaryMpoData, 0, primaryMpoData.length);
if(primaryBm == null) {
return false;
diff --git a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
index 0cdbed76d..c3120d72b 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
@@ -18,9 +18,10 @@ package com.android.gallery3d.filtershow.pipeline;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.PorterDuff;
+import android.graphics.Color;
import android.renderscript.Allocation;
import android.renderscript.RenderScript;
+
import com.android.gallery3d.filtershow.cache.BitmapCache;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
@@ -57,8 +58,8 @@ public class Buffer {
}
public synchronized void useBitmap(Bitmap bitmap) {
+ mBitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(mBitmap);
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(bitmap, 0, 0, null);
}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
index 1640dac66..445407df9 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
@@ -42,6 +42,7 @@ import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.filters.ImageFilter;
@@ -333,15 +334,19 @@ public class ImagePreset {
public void removeFilter(FilterRepresentation filterRepresentation) {
if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER
- || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) {
+ || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_DUALCAM
+ || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation filter = mFilters.elementAt(i);
if (filter.getFilterType() == filterRepresentation.getFilterType()) {
mFilters.remove(i);
// reset fusion underlay image.
- if(filter instanceof FilterDualCamFusionRepresentation) {
+ if(filter instanceof FilterDualCamFusionRepresentation ||
+ filter instanceof FilterTruePortraitFusionRepresentation) {
MasterImage.getImage().setFusionUnderlay(null);
+ MasterImage.getImage().setScaleFactor(1);
+ MasterImage.getImage().resetTranslation();
}
break;
}
@@ -399,6 +404,11 @@ public class ImagePreset {
if (!isNoneDualCamFilter(representation)) {
mFilters.add(representation);
}
+ } else if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ removeFilter(representation);
+ if (!isNoneTruePortraitFilter(representation)) {
+ mFilters.add(representation);
+ }
} else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) {
boolean replaced = false;
for (int i = 0; i < mFilters.size(); i++) {
@@ -422,6 +432,7 @@ public class ImagePreset {
// Enforces Filter type ordering for borders and dual cam
FilterRepresentation border = null;
FilterRepresentation dualcam = null;
+ FilterRepresentation trueportrait = null;
for (int i = 0; i < mFilters.size();) {
FilterRepresentation rep = mFilters.elementAt(i);
if (rep.getFilterType() == FilterRepresentation.TYPE_BORDER) {
@@ -432,6 +443,10 @@ public class ImagePreset {
dualcam = rep;
mFilters.remove(i);
continue;
+ } else if (rep.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ trueportrait = rep;
+ mFilters.remove(i);
+ continue;
}
i++;
}
@@ -448,6 +463,16 @@ public class ImagePreset {
}
mFilters.add(i, dualcam);
}
+ if (trueportrait != null) {
+ int i = 0;
+ for (; i < mFilters.size(); i++) {
+ FilterRepresentation rep = mFilters.elementAt(i);
+ if (rep.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
+ break;
+ }
+ }
+ mFilters.add(i, trueportrait);
+ }
}
private boolean isNoneBorderFilter(FilterRepresentation representation) {
@@ -465,6 +490,11 @@ public class ImagePreset {
((FilterDualCamSketchRepresentation) representation).getTextId() == R.string.none;
}
+ private boolean isNoneTruePortraitFilter(FilterRepresentation representation) {
+ return representation.getTextId() == R.string.none &&
+ representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT;
+ }
+
public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation representation = mFilters.elementAt(i);
@@ -478,6 +508,7 @@ public class ImagePreset {
public Bitmap apply(Bitmap original, FilterEnvironment environment) {
Bitmap bitmap = original;
bitmap = applyDualCamera(bitmap, environment);
+ bitmap = applyTruePortrait(bitmap, environment);
bitmap = applyFilters(bitmap, -1, -1, environment);
return applyBorder(bitmap, environment);
}
@@ -540,6 +571,25 @@ public class ImagePreset {
return bitmap;
}
+ public Bitmap applyTruePortrait(Bitmap bitmap, FilterEnvironment environment) {
+ // Apply trueportrait filters
+ // Returns a new bitmap.
+ for (FilterRepresentation representation:mFilters) {
+ if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ Bitmap tmp = bitmap;
+ bitmap = environment.applyRepresentation(representation, bitmap);
+ if (tmp != bitmap) {
+ environment.cache(tmp);
+ }
+ if (environment.needsStop()) {
+ return bitmap;
+ }
+ }
+ }
+
+ return bitmap;
+ }
+
public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) {
// get the border from the list of filters.
FilterRepresentation border = getFilterRepresentationForType(
@@ -580,6 +630,10 @@ public class ImagePreset {
// skip the dual cam as it's already applied.
continue;
}
+ if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ // skip the true portrait as it's already applied.
+ continue;
+ }
Bitmap tmp = bitmap;
bitmap = environment.applyRepresentation(representation, bitmap);
if (tmp != bitmap) {
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
index 86d4c92c1..3948b6eea 100644..100755
--- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
@@ -184,8 +184,8 @@ public class ProcessingService extends Service {
@Override
public void onDestroy() {
- tearDownPipeline();
mProcessingTaskController.quit();
+ tearDownPipeline();
MasterImage.setMaster(null);
}
@@ -285,7 +285,7 @@ public class ProcessingService extends Service {
if (exit) {
// terminate now
Bundle bundle = new Bundle();
- bundle.putString(KEY_URL, result.toString());
+ bundle.putString(KEY_URL, result == null ? null : result.toString());
bundle.putLong(KEY_REQUEST_ID, requestId);
bundle.putBoolean(KEY_DUALCAM, releaseDualCam);
broadcastState(SAVE_IMAGE_COMPLETE_ACTION, bundle);
@@ -307,6 +307,7 @@ public class ProcessingService extends Service {
filtersManager.addTrueScanner();
filtersManager.addHazeBuster();
filtersManager.addSeeStraight();
+ filtersManager.addTruePortrait(this);
FiltersManager highresFiltersManager = FiltersManager.getHighresManager();
highresFiltersManager.addLooks(this);
@@ -318,6 +319,7 @@ public class ProcessingService extends Service {
highresFiltersManager.addTrueScanner();
highresFiltersManager.addHazeBuster();
highresFiltersManager.addSeeStraight();
+ highresFiltersManager.addTruePortrait(this);
}
private void tearDownPipeline() {
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveImage.java b/src/com/android/gallery3d/filtershow/tools/SaveImage.java
index 0f615da25..87492a335 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java
@@ -50,7 +50,9 @@ import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.CachingPipeline;
@@ -361,35 +363,11 @@ public class SaveImage {
if (mPreviewImage != null) {
Bitmap previewBmp;
// Check for Fusion
- FilterDualCamFusionRepresentation fusionRep =
- (FilterDualCamFusionRepresentation) preset.getFilterWithSerializationName(
- FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
+ FilterFusionRepresentation fusionRep = findFusionRepresentation(preset);
boolean hasFusion = (fusionRep != null && fusionRep.hasUnderlay());
if(hasFusion) {
- // fusion. decode underlay image and get dest rect
- Uri underLayUri = Uri.parse(fusionRep.getUnderlay());
- Bitmap underlay = ImageLoader.loadConstrainedBitmap(underLayUri, mContext,
- Math.max(mPreviewImage.getWidth(), mPreviewImage.getHeight()), null, false);
- RectF destRect = new RectF();
- Rect imageBounds = MasterImage.getImage().getImageBounds();
- Rect underlayBounds = MasterImage.getImage().getFusionBounds();
- float underlayScaleFactor = (float)underlay.getWidth()
- / (float)underlayBounds.width();
-
- destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
- destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
- destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
- destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
-
- Canvas canvas = new Canvas(underlay);
- Paint paint = new Paint();
- paint.reset();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
-
- canvas.drawBitmap(mPreviewImage, null, destRect, paint);
- previewBmp = underlay;
+ previewBmp = flattenFusion(Uri.parse(fusionRep.getUnderlay()), mPreviewImage,
+ Math.max(mPreviewImage.getWidth(), mPreviewImage.getHeight()), 0);
} else {
previewBmp = mPreviewImage;
}
@@ -464,31 +442,11 @@ public class SaveImage {
bitmap = pipeline.renderFinalImage(bitmap, preset);
// Check for Fusion
- FilterDualCamFusionRepresentation fusionRep = (FilterDualCamFusionRepresentation) preset.getFilterWithSerializationName(
- FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
-
- if(fusionRep != null && fusionRep.hasUnderlay()) {
- // fusion. decode underlay image and get dest rect
- Uri underLayUri = Uri.parse(fusionRep.getUnderlay());
- Bitmap underlay = ImageLoader.loadBitmapWithBackouts(mContext, underLayUri, sampleSize);
- RectF destRect = new RectF();
- Rect imageBounds = MasterImage.getImage().getImageBounds();
- Rect underlayBounds = MasterImage.getImage().getFusionBounds();
- float underlayScaleFactor = (float)underlay.getWidth() / (float)underlayBounds.width();
-
- destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
- destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
- destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
- destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
-
- Canvas canvas = new Canvas(underlay);
- Paint paint = new Paint();
- paint.reset();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
-
- canvas.drawBitmap(bitmap, null, destRect, paint);
+ FilterFusionRepresentation fusionRep = findFusionRepresentation(preset);
+ boolean hasFusion = (fusionRep != null && fusionRep.hasUnderlay());
+ if(hasFusion) {
+ Bitmap underlay = flattenFusion(
+ Uri.parse(fusionRep.getUnderlay()), bitmap, 0, sampleSize);
bitmap.recycle();
bitmap = underlay;
@@ -832,4 +790,56 @@ public class SaveImage {
return false;
}
+ private FilterFusionRepresentation findFusionRepresentation(ImagePreset preset) {
+ FilterDualCamFusionRepresentation dcRepresentation =
+ (FilterDualCamFusionRepresentation)preset.getFilterWithSerializationName(
+ FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
+ FilterTruePortraitFusionRepresentation tpRepresentation =
+ (FilterTruePortraitFusionRepresentation)preset.getFilterWithSerializationName(
+ FilterTruePortraitFusionRepresentation.SERIALIZATION_NAME);
+
+ FilterFusionRepresentation fusionRep = null;
+
+ if(dcRepresentation != null)
+ fusionRep = (FilterFusionRepresentation) dcRepresentation;
+ else if (tpRepresentation != null)
+ fusionRep = (FilterFusionRepresentation) tpRepresentation;
+
+ return fusionRep;
+ }
+
+ private Bitmap flattenFusion(Uri underlayUri, Bitmap bitmap, int sizeConstraint, int sampleSize) {
+ // fusion. decode underlay image and get dest rect
+
+ Bitmap underlay = null;
+
+ if(sizeConstraint != 0) {
+ underlay = ImageLoader.loadConstrainedBitmap(underlayUri, mContext,
+ sizeConstraint, null, false);
+ } else if (sampleSize != 0) {
+ underlay = ImageLoader.loadBitmapWithBackouts(mContext, underlayUri, sampleSize);
+ }
+
+ RectF destRect = new RectF();
+ Rect imageBounds = MasterImage.getImage().getImageBounds();
+ Rect underlayBounds = MasterImage.getImage().getFusionBounds();
+ float underlayScaleFactor = (float)underlay.getWidth()
+ / (float)underlayBounds.width();
+
+ destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
+ destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
+ destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
+ destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
+
+ Canvas canvas = new Canvas(underlay);
+ Paint paint = new Paint();
+ paint.reset();
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+
+ canvas.drawBitmap(bitmap, null, destRect, paint);
+
+ return underlay;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java b/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java
new file mode 100644
index 000000000..03972638c
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.tools;
+
+import java.util.Stack;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.v4.app.FragmentManager;
+import android.util.Log;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData;
+import com.android.gallery3d.filtershow.ui.AlertMsgDialog;
+
+public class TruePortraitNativeEngine {
+ private static final String TAG = "TruePortraitNativeEngine";
+ static {
+ try {
+ System.loadLibrary("jni_trueportrait");
+ mLibLoaded = true;
+ Log.v(TAG, "successfully loaded true portrait lib");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "failed to load true portrait lib");
+ mLibLoaded = false;
+ }
+ }
+
+ public static enum EffectType {
+ BLUR,
+ MOTION_BLUR,
+ HALO,
+ SKETCH
+ };
+
+ private static final int MASK_UPDATE_FOREGROUND = 0x7F000000;
+ private static final int MASK_UPDATE_BACKGROUND = 0x81000000;
+
+ private static boolean mLibLoaded;
+ private static TruePortraitNativeEngine mInstance;
+
+ private Bitmap mSketchBm;
+ private boolean mFacesDetected;
+ private Point mPreviewSize = new Point();
+ private Bitmap mUpdateBm;
+
+ private TruePortraitNativeEngine() {}
+
+ public static void createInstance() {
+ if(mInstance == null) {
+ mInstance = new TruePortraitNativeEngine();
+ }
+ }
+
+ public static TruePortraitNativeEngine getInstance() {
+ createInstance();
+ return mInstance;
+ }
+
+ public boolean isLibLoaded() {
+ return mLibLoaded;
+ }
+
+ public boolean init(Context context, Bitmap src, Rect[] faces) {
+ setFacesDetected(true);
+ if(nativeInit(src, faces.length, faces)) {
+ nativeGetPreviewSize(mPreviewSize);
+ mSketchBm = BitmapFactory.decodeResource(context.getResources(), R.raw.sketch_bm);
+ return true;
+ } else {
+ mSketchBm = null;
+ return false;
+ }
+ }
+
+ public void release() {
+ if(mUpdateBm != null) {
+ mUpdateBm.recycle();
+ mUpdateBm = null;
+ }
+
+ if(mSketchBm != null) {
+ mSketchBm.recycle();
+ mSketchBm = null;
+ }
+
+ nativeRelease();
+ }
+
+ public void setFacesDetected(boolean detected) {
+ mFacesDetected = detected;
+ }
+
+ public boolean facesDetected() {
+ return mFacesDetected;
+ }
+
+ public void showNoFaceDetectedDialog(FragmentManager fragmentManager) {
+ AlertMsgDialog dialog = new AlertMsgDialog(R.string.trueportrait, R.string.trueportrait_no_face);
+ dialog.show(fragmentManager, "tp_no_face");
+ }
+
+ public boolean applyEffect(EffectType type, int intensity, Bitmap outBm) {
+ boolean result = false;
+ switch(type) {
+ case BLUR:
+ result = nativeApplyBlur(intensity, outBm);
+ break;
+ case MOTION_BLUR:
+ result = nativeApplyMotionBlur(intensity, outBm);
+ break;
+ case HALO:
+ result = nativeApplyHalo(intensity, outBm);
+ break;
+ case SKETCH:
+ result = nativeApplySketch(outBm, mSketchBm);
+ break;
+ }
+
+ return result;
+ }
+
+ public Bitmap getMask() {
+ Bitmap mask = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ALPHA_8);
+ if(mask != null) {
+ nativeGetPreviewMask(mask);
+ }
+
+ return mask;
+ }
+
+ public Bitmap getPreview() {
+ Bitmap previewBm = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ARGB_8888);
+ if(previewBm != null) {
+ nativeGetPreviewImage(previewBm);
+ }
+
+ return previewBm;
+ }
+
+ public boolean updateMask(Stack<StrokeData> edits) {
+ if(mUpdateBm == null) {
+ mUpdateBm = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ALPHA_8);
+ }
+
+ mUpdateBm.eraseColor(Color.TRANSPARENT);
+ Canvas canvas = new Canvas(mUpdateBm);
+ for(StrokeData sd:edits) {
+ drawEdit(canvas, sd);
+ }
+
+ // DEBUG
+ for(int i = 0; i<mPreviewSize.y; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ ");
+ for(int j = 0; j<mPreviewSize.x; j++) {
+ int pixel = mUpdateBm.getPixel(j, i);
+ sb.append(Color.alpha(pixel));
+ sb.append(" ");
+ }
+ sb.append("]");
+ Log.e(TAG, sb.toString());
+ }
+ //
+ return nativeUpdatePreviewMask(mUpdateBm);
+ }
+
+ private void drawEdit(Canvas canvas, StrokeData sd) {
+ if (sd == null) {
+ return;
+ }
+ if (sd.mPath == null) {
+ return;
+ }
+ // USER_INPUT_MASK_UNCHANGED_VALUE = 0
+ // USER_INPUT_MASK_BACKGROUND_VALUE = 129
+ // USER_INPUT_MASK_FOREGROUND_VALUE = 127
+ Paint paint = new Paint();
+ paint.setAntiAlias(false);
+ paint.setStyle(Style.STROKE);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ if(sd.mColor == Color.TRANSPARENT)
+ paint.setColor(MASK_UPDATE_BACKGROUND);
+ else
+ paint.setColor(MASK_UPDATE_FOREGROUND);
+ paint.setStrokeWidth(sd.mRadius);
+
+ canvas.drawPath(sd.mPath, paint);
+ }
+
+ native public boolean nativeInit(Bitmap srcRGBA, int numFaces, Rect[] faces);
+
+ native public void nativeRelease();
+
+ native public boolean nativeGetPreviewSize(Point point);
+
+ native public boolean nativeGetPreviewImage(Bitmap outBm);
+
+ native public boolean nativeGetPreviewMask(Bitmap outBm);
+
+ native public boolean nativeUpdatePreviewMask(Bitmap mask);
+
+ native public boolean nativeApplyBlur(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplyMotionBlur(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplyHalo(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplySketch(Bitmap outBm, Bitmap sketchBm);
+
+ native public boolean nativeGetForegroundImg(Bitmap outBm);
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java b/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java
new file mode 100644
index 000000000..2041eb2ce
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.ui;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+import org.codeaurora.gallery.R;
+
+public class AlertMsgDialog extends DialogFragment {
+ private int mTitleId;
+ private int mMessageId;
+
+ public AlertMsgDialog(int titleId, int msgId) {
+ mTitleId = titleId;
+ mMessageId = msgId;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
+ ab.setTitle(mTitleId);
+ ab.setMessage(mMessageId);
+ ab.setCancelable(false);
+ ab.setNeutralButton(R.string.ok, null);
+ return ab.create();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java b/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java
new file mode 100644
index 000000000..aad403bd1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.filtershow.ui;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class DoNotShowAgainDialog extends DialogFragment {
+ private int mSharedPrefKeyId;
+ private int mTitleId;
+ private int mMessageId;
+ private CheckBox mDoNotShowAgainChk;
+
+ public DoNotShowAgainDialog(int titleId, int msgId, int sharedPrefKeyId) {
+ mTitleId = titleId;
+ mMessageId = msgId;
+ mSharedPrefKeyId = sharedPrefKeyId;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View view = inflater.inflate(R.layout.do_not_show_again_dialog, null);
+ TextView message = (TextView) view.findViewById(R.id.message);
+ message.setText(mMessageId);
+ mDoNotShowAgainChk = (CheckBox) view.findViewById(R.id.do_not_show_chk);
+
+ AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
+ ab.setTitle(mTitleId);
+ ab.setView(view);
+ ab.setCancelable(false);
+ ab.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ Context context = getActivity();
+ GalleryUtils.setBooleanPref(context,
+ context.getString(mSharedPrefKeyId), mDoNotShowAgainChk.isChecked());
+ }
+ });
+ return ab.create();
+ }
+}
diff --git a/src/com/android/gallery3d/glrenderer/GLES11Canvas.java b/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
index 7013c3d1f..38ee50a5e 100644..100755
--- a/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
+++ b/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
@@ -24,6 +24,7 @@ import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;
+import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.util.IntArray;
@@ -617,7 +618,11 @@ public class GLES11Canvas implements GLCanvas {
gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
// We use 565 or 8888 format, so set the alignment to 2 bytes/pixel.
- gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2);
+ if (ApiHelper.USE_888_PIXEL_FORMAT) {
+ gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 2);
+ } else {
+ gl.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
+ }
}
public void setTexEnvMode(int mode) {
diff --git a/src/com/android/gallery3d/mpo/MpoParser.java b/src/com/android/gallery3d/mpo/MpoParser.java
index d859c05b4..b872db640 100644
--- a/src/com/android/gallery3d/mpo/MpoParser.java
+++ b/src/com/android/gallery3d/mpo/MpoParser.java
@@ -37,6 +37,8 @@ import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.HashMap;
import android.content.ContentResolver;
import android.content.Context;
@@ -62,12 +64,13 @@ public class MpoParser {
private int mMpHeaderOffset;
private int mIfd1Offset;
private int mMpEntryOffset;
- private MpEntry mPrimaryEntry;
- private MpEntry mSecondaryEntry;
+ private HashMap<Short, MpoTag> mTags = new HashMap<Short, MpoTag>();
+ private ArrayList<MpEntry> mMpEntries = new ArrayList<MpEntry>();
private MpoParser(Context context, Uri uri) {
mContentResolver = context.getContentResolver();
mUri = uri;
+ mTags.clear();
InputStream is = null;
try {
@@ -136,41 +139,61 @@ public class MpoParser {
mDataStream.skipTo(mIfd1Offset);
int count = mDataStream.readShort();
// add 6 (2 for count, 4 for offset to next IFD)
+ for(int i=0; i<count; i++) {
+ MpoTag tag = readMpoTag();
+ mTags.put(tag.mId, tag);
+ }
+
mMpEntryOffset = mIfd1Offset + (count*MP_INDEX_FIELD_SIZE_BYTES) + 6;
}
- private MpEntry readMpEntryData() {
- try {
- mDataStream.skipTo(mMpEntryOffset);
-
- mPrimaryEntry = new MpEntry();
- mPrimaryEntry.mImgAttribute = mDataStream.readInt();
- mPrimaryEntry.mImgSize = mDataStream.readInt();
- mPrimaryEntry.mImgDataOffset = mDataStream.readInt();
- mPrimaryEntry.mDepImg1Entry = mDataStream.readShort();
- mPrimaryEntry.mDepImg2Entry = mDataStream.readShort();
-
- mSecondaryEntry = new MpEntry();
- mSecondaryEntry.mImgAttribute = mDataStream.readInt();
- mSecondaryEntry.mImgSize = mDataStream.readInt();
- mSecondaryEntry.mImgDataOffset = mDataStream.readInt();
- mSecondaryEntry.mDepImg1Entry = mDataStream.readShort();
- mSecondaryEntry.mDepImg2Entry = mDataStream.readShort();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ private MpoTag readMpoTag() throws IOException {
+ MpoTag tag = new MpoTag();
+ tag.mId = mDataStream.readShort();
+ tag.mType = mDataStream.readShort();
+ tag.mCount = mDataStream.readInt();
+ tag.mData = mDataStream.readInt();
+ return tag;
+ }
+
+ private void readMpEntryData() throws IOException {
+ MpoTag numImagesTag = mTags.get((short)0xB001);
+ int numImages = numImagesTag.mData;
- return mPrimaryEntry;
+ mDataStream.skipTo(mMpEntryOffset);
+
+ for(int i=0; i<numImages; i++) {
+ MpEntry mpEntry = new MpEntry();
+ mpEntry.mImgAttribute = mDataStream.readInt();
+ mpEntry.mImgSize = mDataStream.readInt();
+ mpEntry.mImgDataOffset = mDataStream.readInt();
+ mpEntry.mDepImg1Entry = mDataStream.readShort();
+ mpEntry.mDepImg2Entry = mDataStream.readShort();
+ mMpEntries.add(mpEntry);
+ }
}
public byte[] readImgData(boolean primary) {
MpEntry mpEntry = null;
byte[] data = null;
+ if(mMpEntries.size() < 2){
+ // not enough entries were read.
+ return null;
+ }
+
if(primary) {
- mpEntry = mPrimaryEntry;
+ if(mMpEntries.size() > 2) {
+ mpEntry = mMpEntries.get(1);
+ } else {
+ mpEntry = mMpEntries.get(0);
+ }
} else {
- mpEntry = mSecondaryEntry;
+ if(mMpEntries.size() > 2) {
+ mpEntry = mMpEntries.get(2);
+ } else {
+ mpEntry = mMpEntries.get(1);
+ }
}
if(mpEntry == null)
@@ -288,4 +311,12 @@ public class MpoParser {
short mDepImg1Entry;
short mDepImg2Entry;
}
-} \ No newline at end of file
+
+ class MpoTag {
+ short mId;
+ short mType;
+ int mCount;
+ int mData;
+ }
+}
+
diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java
index 4765c6838..04d361a19 100644
--- a/src/com/android/gallery3d/ui/ActionModeHandler.java
+++ b/src/com/android/gallery3d/ui/ActionModeHandler.java
@@ -138,6 +138,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
}
public void startActionMode() {
+ mMenuExecutor.setLeaving(false);
Activity a = mActivity;
// mActionMode = a.startActionMode(this);
mActionMode = mActivity.getToolbar().startActionMode(this);
@@ -213,6 +214,7 @@ public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickLi
if (itemId == R.id.action_select_all) {
updateSupportedOperation();
mMenuExecutor.onMenuClicked(itemId, null, false, true);
+ mSelectionMenu.setLeaving(mMenuExecutor.isLeaving());
}
return true;
} finally {
diff --git a/src/com/android/gallery3d/ui/GLRoot.java b/src/com/android/gallery3d/ui/GLRoot.java
index caa36c334..50ba2e4d2 100644..100755
--- a/src/com/android/gallery3d/ui/GLRoot.java
+++ b/src/com/android/gallery3d/ui/GLRoot.java
@@ -45,8 +45,6 @@ public interface GLRoot {
public int getDisplayRotation();
public int getCompensation();
public Matrix getCompensationMatrix();
- public void freeze();
- public void unfreeze();
public void setLightsOutMode(boolean enabled);
public Context getContext();
diff --git a/src/com/android/gallery3d/ui/GLRootView.java b/src/com/android/gallery3d/ui/GLRootView.java
index 5d9621b6d..579fd05d0 100644..100755
--- a/src/com/android/gallery3d/ui/GLRootView.java
+++ b/src/com/android/gallery3d/ui/GLRootView.java
@@ -105,9 +105,6 @@ public class GLRootView extends GLSurfaceView
private final IdleRunner mIdleRunner = new IdleRunner();
private final ReentrantLock mRenderLock = new ReentrantLock();
- private final Condition mFreezeCondition =
- mRenderLock.newCondition();
- private boolean mFreeze;
private long mLastDrawFinishTime;
private boolean mInDownState = false;
@@ -352,10 +349,6 @@ public class GLRootView extends GLSurfaceView
}
mRenderLock.lock();
- while (mFreeze) {
- mFreezeCondition.awaitUninterruptibly();
- }
-
try {
onDrawFrameLocked(gl);
} finally {
@@ -542,7 +535,6 @@ public class GLRootView extends GLSurfaceView
@Override
public void onPause() {
- unfreeze();
super.onPause();
if (DEBUG_PROFILE) {
Log.d(TAG, "Stop profiling");
@@ -572,20 +564,6 @@ public class GLRootView extends GLSurfaceView
return mCompensationMatrix;
}
- @Override
- public void freeze() {
- mRenderLock.lock();
- mFreeze = true;
- mRenderLock.unlock();
- }
-
- @Override
- public void unfreeze() {
- mRenderLock.lock();
- mFreeze = false;
- mFreezeCondition.signalAll();
- mRenderLock.unlock();
- }
@Override
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@@ -602,40 +580,4 @@ public class GLRootView extends GLSurfaceView
setSystemUiVisibility(flags);
}
- // We need to unfreeze in the following methods and in onPause().
- // These methods will wait on GLThread. If we have freezed the GLRootView,
- // the GLThread will wait on main thread to call unfreeze and cause dead
- // lock.
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- unfreeze();
- super.surfaceChanged(holder, format, w, h);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- unfreeze();
- super.surfaceCreated(holder);
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- unfreeze();
- super.surfaceDestroyed(holder);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- unfreeze();
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- unfreeze();
- } finally {
- super.finalize();
- }
- }
}
diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java
index c57e848e3..8f3409131 100644
--- a/src/com/android/gallery3d/ui/MenuExecutor.java
+++ b/src/com/android/gallery3d/ui/MenuExecutor.java
@@ -67,6 +67,7 @@ public class MenuExecutor {
// wait the operation to finish when we want to stop it.
private boolean mWaitOnStop;
private boolean mPaused;
+ private boolean isLeaving = false;
private final AbstractGalleryActivity mActivity;
private final SelectionManager mSelectionManager;
@@ -233,6 +234,14 @@ public class MenuExecutor {
return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType);
}
+ public void setLeaving(boolean leaving) {
+ isLeaving = leaving;
+ }
+
+ public boolean isLeaving() {
+ return isLeaving;
+ }
+
private void onMenuClicked(int action, ProgressListener listener) {
onMenuClicked(action, listener, false, true);
}
@@ -243,6 +252,7 @@ public class MenuExecutor {
switch (action) {
case R.id.action_select_all:
if (mSelectionManager.inSelectAllMode()) {
+ isLeaving = true;
mSelectionManager.deSelectAll();
} else {
mSelectionManager.selectAll();
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index 42888f33d..7ee799c03 100644..100755
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -128,7 +128,6 @@ public class PhotoView extends GLView {
public void onFullScreenChanged(boolean full);
public void onActionBarAllowed(boolean allowed);
public void onActionBarWanted();
- public void onCurrentImageUpdated();
public void onDeleteImage(Path path, int offset);
public void onUndoDeleteImage();
public void onCommitDeleteImage();
@@ -469,9 +468,6 @@ public class PhotoView extends GLView {
}
public void notifyImageChange(int index) {
- if (index == 0) {
- mListener.onCurrentImageUpdated();
- }
mPictures.get(index).reload();
setPictureSize(index);
invalidate();
diff --git a/src/com/android/gallery3d/ui/SelectionManager.java b/src/com/android/gallery3d/ui/SelectionManager.java
index 85616263c..da61bf19c 100644..100755
--- a/src/com/android/gallery3d/ui/SelectionManager.java
+++ b/src/com/android/gallery3d/ui/SelectionManager.java
@@ -17,6 +17,9 @@
package com.android.gallery3d.ui;
import com.android.gallery3d.app.AbstractGalleryActivity;
+import com.android.gallery3d.app.AlbumSetDataLoader;
+import com.android.gallery3d.app.TimeLineDataLoader;
+import com.android.gallery3d.data.ContentListener;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
@@ -27,7 +30,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
-public class SelectionManager {
+public class SelectionManager implements TimeLineDataLoader.DataListener, AlbumSetDataLoader.DataListener{
@SuppressWarnings("unused")
private static final String TAG = "SelectionManager";
@@ -47,6 +50,26 @@ public class SelectionManager {
/** mTotalSelectable is the count of items
* exclude not selectable such as Title item in TimeLine. */
private int mTotalSelectable;
+ private TimeLineDataLoader mTimeLineDataLoader;
+ private AlbumSetDataLoader mAlbumSetDataLoader;
+
+ @Override
+ public void onContentChanged(int index) {
+ }
+
+ @Override
+ public void onSizeChanged(int size) {
+ if (mInverseSelection) {
+ selectAll();
+ }
+ }
+
+ @Override
+ public void onSizeChanged() {
+ if (mInverseSelection) {
+ selectAll();
+ }
+ }
public interface SelectionListener {
public void onSelectionModeChange(int mode);
@@ -99,6 +122,12 @@ public class SelectionManager {
mInSelectionMode = true;
if (mListener != null) mListener.onSelectionModeChange(ENTER_SELECTION_MODE);
+ if (mAlbumSetDataLoader != null) {
+ mAlbumSetDataLoader.setModelListener(this);
+ }
+ if (mTimeLineDataLoader != null) {
+ mTimeLineDataLoader.setDataListener(this);
+ }
}
public void leaveSelectionMode() {
@@ -108,6 +137,12 @@ public class SelectionManager {
mInverseSelection = false;
mClickedSet.clear();
if (mListener != null) mListener.onSelectionModeChange(LEAVE_SELECTION_MODE);
+ if (mAlbumSetDataLoader != null) {
+ mAlbumSetDataLoader.removeModelListener(this);
+ }
+ if (mTimeLineDataLoader != null) {
+ mTimeLineDataLoader.removeDataListener(this);
+ }
}
public boolean isItemSelected(Path itemId) {
@@ -293,4 +328,12 @@ public class SelectionManager {
mSourceMediaSet = set;
mTotal = -1;
}
+
+ public void setTimeLineDataLoader(TimeLineDataLoader loader) {
+ mTimeLineDataLoader = loader;
+ }
+
+ public void setAlbumSetDataLoader(AlbumSetDataLoader loader) {
+ mAlbumSetDataLoader = loader;
+ }
}
diff --git a/src/com/android/gallery3d/ui/SelectionMenu.java b/src/com/android/gallery3d/ui/SelectionMenu.java
index 4ee60b437..07815cd80 100644
--- a/src/com/android/gallery3d/ui/SelectionMenu.java
+++ b/src/com/android/gallery3d/ui/SelectionMenu.java
@@ -31,6 +31,7 @@ public class SelectionMenu implements OnClickListener {
private final Context mContext;
private final Button mButton;
private final PopupList mPopupList;
+ private boolean isLeaving = false;
public SelectionMenu(Context context, Button button, OnPopupItemClickListener listener) {
mContext = context;
@@ -44,6 +45,7 @@ public class SelectionMenu implements OnClickListener {
@Override
public void onClick(View v) {
+ if (isLeaving) return;
mPopupList.show();
}
@@ -58,4 +60,8 @@ public class SelectionMenu implements OnClickListener {
public void setTitle(CharSequence title) {
mButton.setText(title);
}
+
+ public void setLeaving(boolean leaving) {
+ isLeaving = leaving;
+ }
}
diff --git a/src/com/android/gallery3d/ui/TimeLineSlotView.java b/src/com/android/gallery3d/ui/TimeLineSlotView.java
index 329ea75e3..7dcf4ef5f 100644..100755
--- a/src/com/android/gallery3d/ui/TimeLineSlotView.java
+++ b/src/com/android/gallery3d/ui/TimeLineSlotView.java
@@ -589,7 +589,9 @@ public class TimeLineSlotView extends GLView {
if (mSlotCount != null) {
Slot begin = getSlotByPosition(0, mScrollPosition, true, false),
end = getSlotByPosition(0, mScrollPosition + mHeight, true, true);
- if (begin != null && end != null) {
+ if (begin == null && end != null && end.index == 0) {
+ setVisibleRange(0, 0);
+ } else if (begin != null && end != null) {
setVisibleRange(begin.index, end.index);
}
}
diff --git a/src/com/android/gallery3d/util/GalleryUtils.java b/src/com/android/gallery3d/util/GalleryUtils.java
index a0580016b..3a50dbfbd 100644
--- a/src/com/android/gallery3d/util/GalleryUtils.java
+++ b/src/com/android/gallery3d/util/GalleryUtils.java
@@ -423,7 +423,7 @@ public class GalleryUtils {
return (h > 0 && w / h >= 2);
}
// Newly added methods
- public static int getIntPref(Context context, String name, int def) {
+ public static int getIntPref(Context context, String name, int def) {
SharedPreferences prefs =
context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
return prefs.getInt(name, def);
@@ -437,6 +437,34 @@ public class GalleryUtils {
ed.commit();
}
+ public static boolean getBooleanPref(Context context, String name, boolean def) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ return prefs.getBoolean(name, def);
+ }
+
+ public static void setBooleanPref(Context context, String name, boolean value) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ Editor ed = prefs.edit();
+ ed.putBoolean(name, value);
+ ed.commit();
+ }
+
+ public static String getStringPref(Context context, String name, String def) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ return prefs.getString(name, def);
+ }
+
+ public static void setStringPref(Context context, String name, String value) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ Editor ed = prefs.edit();
+ ed.putString(name, value);
+ ed.commit();
+ }
+
public static boolean isTelephonyCallInProgress(Context context) {
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java b/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
index a5c7fb043..99eb33ec8 100644
--- a/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
+++ b/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
@@ -24,7 +24,7 @@ import android.util.Log;
public class FaceDetect {
private static final String TAG = "FaceDetect";
- private int mHandle = 0;
+ private long mHandle = 0;
static {
try {
@@ -71,9 +71,9 @@ public class FaceDetect {
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);
}
diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
index 2d30d8f30..bee9560a4 100644
--- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
+++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
@@ -42,5 +42,9 @@ public class EditorManager {
editorPlaceHolder.addEditor(new TrueScannerEditor());
editorPlaceHolder.addEditor(new HazeBusterEditor());
editorPlaceHolder.addEditor(new SeeStraightEditor());
+ editorPlaceHolder.addEditor(new EditorTruePortraitBasic());
+ editorPlaceHolder.addEditor(new EditorTruePortraitImageOnly());
+ editorPlaceHolder.addEditor(new EditorTruePortraitMask());
+ editorPlaceHolder.addEditor(new EditorTruePortraitFusion());
}
}