summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-08-12 16:08:27 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-08-12 16:08:27 -0700
commite6c5375a2310e4cafc982873e6b89bffc9ca2ea5 (patch)
tree9c91f90fd426014f061173f6225ad6fe55bd5446
parentb93beaf65349dc3b4522c2506d6cec1ceb64b618 (diff)
parentf19b070884f491ecae432914131a302876e1fcf6 (diff)
downloadandroid_packages_apps_Gallery2-e6c5375a2310e4cafc982873e6b89bffc9ca2ea5.tar.gz
android_packages_apps_Gallery2-e6c5375a2310e4cafc982873e6b89bffc9ca2ea5.tar.bz2
android_packages_apps_Gallery2-e6c5375a2310e4cafc982873e6b89bffc9ca2ea5.zip
Merge "Gallery: Add TruePortrait post proc feature"
-rw-r--r--Android.mk2
-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_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
-rw-r--r--res/values/filtershow_ids.xml4
-rw-r--r--res/values/filtershow_strings.xml24
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java240
-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.java8
-rw-r--r--src/com/android/gallery3d/filtershow/category/MainPanel.java68
-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
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java195
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java58
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java46
-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
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/MasterImage.java8
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/Buffer.java5
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java58
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java2
-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
-rw-r--r--src/com/android/gallery3d/util/GalleryUtils.java30
-rw-r--r--src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java4
137 files changed, 3673 insertions, 241 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/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_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/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/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 157087972..c12635f06 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -57,7 +57,6 @@ 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;
@@ -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,13 +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;
@@ -176,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;
@@ -195,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>();
@@ -365,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;
@@ -419,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) {
@@ -484,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;
}
}
@@ -540,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() {
@@ -592,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()
@@ -628,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);
@@ -658,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) {
@@ -686,6 +733,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
fillVersions();
fillMakeup();
fillDualCamera();
+ fillTruePortrait();
}
public void setupStatePanel() {
@@ -808,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();
@@ -926,6 +989,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mainPanel.updateDualCameraButton();
}
}
+
+ if(TruePortraitNativeEngine.getInstance().isLibLoaded()) {
+ mLoadTruePortraitTask = new LoadTruePortraitTask();
+ mLoadTruePortraitTask.execute(uri);
+ }
}
private void fillBorders() {
@@ -987,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;
@@ -1006,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
@@ -1085,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) {
@@ -1122,6 +1189,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryMakeupAdapter.reflectImagePreset(preset);
}
mCategoryDualCamAdapter.reflectImagePreset(preset);
+ mCategoryTruePortraitAdapter.reflectImagePreset(preset);
}
public View getMainStatePanelContainer(int id) {
@@ -1221,16 +1289,15 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
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(mPrimaryImgData, mAuxImgData);
}
-
- Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
- if (currentPanel instanceof MainPanel) {
- MainPanel mainPanel = (MainPanel) currentPanel;
- mainPanel.updateDualCameraButton();
- }
}
}
@@ -1288,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;
@@ -1362,6 +1462,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryGeometryAdapter.imageLoaded();
mCategoryFiltersAdapter.imageLoaded();
mCategoryDualCamAdapter.imageLoaded();
+ mCategoryTruePortraitAdapter.imageLoaded();
if(mCategoryMakeupAdapter != null) {
mCategoryMakeupAdapter.imageLoaded();
}
@@ -1421,6 +1522,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mLoadMpoTask.cancel(false);
}
+ if(mLoadTruePortraitTask != null) {
+ mLoadTruePortraitTask.cancel(false);
+ }
+
mUserPresetsManager.close();
unregisterReceiver(mHandlerReceiver);
doUnbindService();
@@ -1515,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;
}
@@ -1560,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);
@@ -1575,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;
}
@@ -1891,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() {
@@ -1942,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 87f347586..3b91f024e 100644
--- a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
@@ -90,6 +90,14 @@ public class CategoryPanel extends Fragment implements View.OnClickListener {
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();
if (mAdapter != null) {
diff --git a/src/com/android/gallery3d/filtershow/category/MainPanel.java b/src/com/android/gallery3d/filtershow/category/MainPanel.java
index 6571c46a3..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;
@@ -40,6 +42,9 @@ 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 {
@@ -56,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";
@@ -69,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;
@@ -105,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);
@@ -139,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);
@@ -204,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) {
@@ -235,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);
}
});
@@ -449,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) {
@@ -492,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/ImageFilterTruePortrait.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
new file mode 100644
index 000000000..86a2a7404
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
@@ -0,0 +1,195 @@
+/*
+ * 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 static Toast sSegmentToast;
+
+ 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");
+ sActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if(sSegmentToast == null) {
+ sSegmentToast = Toast.makeText(sActivity, "No Faces Found", Toast.LENGTH_SHORT);
+ }
+ sSegmentToast.show();
+ }
+ });
+
+ 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/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/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 09bf27bd9..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;
@@ -442,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;
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 b5e9609e2..d42834457 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
@@ -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/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_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());
}
}