diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-08-12 16:08:27 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-08-12 16:08:27 -0700 |
| commit | e6c5375a2310e4cafc982873e6b89bffc9ca2ea5 (patch) | |
| tree | 9c91f90fd426014f061173f6225ad6fe55bd5446 | |
| parent | b93beaf65349dc3b4522c2506d6cec1ceb64b618 (diff) | |
| parent | f19b070884f491ecae432914131a302876e1fcf6 (diff) | |
| download | android_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"
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 Binary files differnew file mode 100644 index 000000000..77c9a5735 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_help.png diff --git a/res/drawable-hdpi/btn_tp_help_sel.png b/res/drawable-hdpi/btn_tp_help_sel.png Binary files differnew file mode 100644 index 000000000..80893dd5f --- /dev/null +++ b/res/drawable-hdpi/btn_tp_help_sel.png diff --git a/res/drawable-hdpi/btn_tp_sel_bg.png b/res/drawable-hdpi/btn_tp_sel_bg.png Binary files differnew file mode 100644 index 000000000..2560ec38a --- /dev/null +++ b/res/drawable-hdpi/btn_tp_sel_bg.png diff --git a/res/drawable-hdpi/btn_tp_sel_bg_sel.png b/res/drawable-hdpi/btn_tp_sel_bg_sel.png Binary files differnew file mode 100644 index 000000000..f2170e1f9 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_sel_bg_sel.png diff --git a/res/drawable-hdpi/btn_tp_touchup.png b/res/drawable-hdpi/btn_tp_touchup.png Binary files differnew file mode 100644 index 000000000..cd450a767 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_touchup.png diff --git a/res/drawable-hdpi/btn_tp_touchup_sel.png b/res/drawable-hdpi/btn_tp_touchup_sel.png Binary files differnew file mode 100644 index 000000000..6b8f18c6c --- /dev/null +++ b/res/drawable-hdpi/btn_tp_touchup_sel.png diff --git a/res/drawable-hdpi/btn_tp_undo.png b/res/drawable-hdpi/btn_tp_undo.png Binary files differnew file mode 100644 index 000000000..de3edd118 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_undo.png diff --git a/res/drawable-hdpi/btn_tp_undo_disabled.png b/res/drawable-hdpi/btn_tp_undo_disabled.png Binary files differnew file mode 100644 index 000000000..e45d76157 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_undo_disabled.png diff --git a/res/drawable-hdpi/btn_tp_undo_sel.png b/res/drawable-hdpi/btn_tp_undo_sel.png Binary files differnew file mode 100644 index 000000000..1d2e5aed1 --- /dev/null +++ b/res/drawable-hdpi/btn_tp_undo_sel.png diff --git a/res/drawable-hdpi/ic_brush_size_large.png b/res/drawable-hdpi/ic_brush_size_large.png Binary files differnew file mode 100644 index 000000000..e67f63d0b --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_large.png diff --git a/res/drawable-hdpi/ic_brush_size_large_sel.png b/res/drawable-hdpi/ic_brush_size_large_sel.png Binary files differnew file mode 100644 index 000000000..c787f8793 --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_large_sel.png diff --git a/res/drawable-hdpi/ic_brush_size_med.png b/res/drawable-hdpi/ic_brush_size_med.png Binary files differnew file mode 100644 index 000000000..7dc3cd181 --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_med.png diff --git a/res/drawable-hdpi/ic_brush_size_med_sel.png b/res/drawable-hdpi/ic_brush_size_med_sel.png Binary files differnew file mode 100644 index 000000000..71b521856 --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_med_sel.png diff --git a/res/drawable-hdpi/ic_brush_size_sm.png b/res/drawable-hdpi/ic_brush_size_sm.png Binary files differnew file mode 100644 index 000000000..afb691741 --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_sm.png diff --git a/res/drawable-hdpi/ic_brush_size_sm_sel.png b/res/drawable-hdpi/ic_brush_size_sm_sel.png Binary files differnew file mode 100644 index 000000000..12601ed99 --- /dev/null +++ b/res/drawable-hdpi/ic_brush_size_sm_sel.png diff --git a/res/drawable-hdpi/ic_tp_bokeh.png b/res/drawable-hdpi/ic_tp_bokeh.png Binary files differnew file mode 100644 index 000000000..c63cf48cb --- /dev/null +++ b/res/drawable-hdpi/ic_tp_bokeh.png diff --git a/res/drawable-hdpi/ic_tp_fusion.png b/res/drawable-hdpi/ic_tp_fusion.png Binary files differnew file mode 100644 index 000000000..8df5c0c94 --- /dev/null +++ b/res/drawable-hdpi/ic_tp_fusion.png diff --git a/res/drawable-hdpi/ic_tp_halo.png b/res/drawable-hdpi/ic_tp_halo.png Binary files differnew file mode 100644 index 000000000..5754b1ba5 --- /dev/null +++ b/res/drawable-hdpi/ic_tp_halo.png diff --git a/res/drawable-hdpi/ic_tp_motion_blur.png b/res/drawable-hdpi/ic_tp_motion_blur.png Binary files differnew file mode 100644 index 000000000..be21d3c9d --- /dev/null +++ b/res/drawable-hdpi/ic_tp_motion_blur.png diff --git a/res/drawable-hdpi/ic_tp_normal.png b/res/drawable-hdpi/ic_tp_normal.png Binary files differnew file mode 100644 index 000000000..f33eb20a7 --- /dev/null +++ b/res/drawable-hdpi/ic_tp_normal.png diff --git a/res/drawable-hdpi/ic_tp_sketch.png b/res/drawable-hdpi/ic_tp_sketch.png Binary files differnew file mode 100644 index 000000000..10aa56063 --- /dev/null +++ b/res/drawable-hdpi/ic_tp_sketch.png diff --git a/res/drawable-hdpi/trueportrait.png b/res/drawable-hdpi/trueportrait.png Binary files differnew file mode 100644 index 000000000..902ffaf5f --- /dev/null +++ b/res/drawable-hdpi/trueportrait.png diff --git a/res/drawable-hdpi/trueportrait_disabled.png b/res/drawable-hdpi/trueportrait_disabled.png Binary files differnew file mode 100644 index 000000000..8708a24d9 --- /dev/null +++ b/res/drawable-hdpi/trueportrait_disabled.png diff --git a/res/drawable-hdpi/trueportrait_select.png b/res/drawable-hdpi/trueportrait_select.png Binary files differnew file mode 100644 index 000000000..6c2e8dd4d --- /dev/null +++ b/res/drawable-hdpi/trueportrait_select.png diff --git a/res/drawable-xhdpi/btn_tp_help.png b/res/drawable-xhdpi/btn_tp_help.png Binary files differnew file mode 100644 index 000000000..c8bee80d7 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_help.png diff --git a/res/drawable-xhdpi/btn_tp_help_sel.png b/res/drawable-xhdpi/btn_tp_help_sel.png Binary files differnew file mode 100644 index 000000000..b5c70a6f3 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_help_sel.png diff --git a/res/drawable-xhdpi/btn_tp_sel_bg.png b/res/drawable-xhdpi/btn_tp_sel_bg.png Binary files differnew file mode 100644 index 000000000..a905e64f2 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_sel_bg.png diff --git a/res/drawable-xhdpi/btn_tp_sel_bg_sel.png b/res/drawable-xhdpi/btn_tp_sel_bg_sel.png Binary files differnew file mode 100644 index 000000000..cdad80b15 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_sel_bg_sel.png diff --git a/res/drawable-xhdpi/btn_tp_touchup.png b/res/drawable-xhdpi/btn_tp_touchup.png Binary files differnew file mode 100644 index 000000000..764042c9b --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_touchup.png diff --git a/res/drawable-xhdpi/btn_tp_touchup_sel.png b/res/drawable-xhdpi/btn_tp_touchup_sel.png Binary files differnew file mode 100644 index 000000000..93f9ef347 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_touchup_sel.png diff --git a/res/drawable-xhdpi/btn_tp_undo.png b/res/drawable-xhdpi/btn_tp_undo.png Binary files differnew file mode 100644 index 000000000..6cb11713f --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_undo.png diff --git a/res/drawable-xhdpi/btn_tp_undo_disabled.png b/res/drawable-xhdpi/btn_tp_undo_disabled.png Binary files differnew file mode 100644 index 000000000..937957e29 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_undo_disabled.png diff --git a/res/drawable-xhdpi/btn_tp_undo_sel.png b/res/drawable-xhdpi/btn_tp_undo_sel.png Binary files differnew file mode 100644 index 000000000..c5ef8e783 --- /dev/null +++ b/res/drawable-xhdpi/btn_tp_undo_sel.png diff --git a/res/drawable-xhdpi/ic_brush_size_large.png b/res/drawable-xhdpi/ic_brush_size_large.png Binary files differnew file mode 100644 index 000000000..4bd4db72c --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_large.png diff --git a/res/drawable-xhdpi/ic_brush_size_large_sel.png b/res/drawable-xhdpi/ic_brush_size_large_sel.png Binary files differnew file mode 100644 index 000000000..c96e76b4b --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_large_sel.png diff --git a/res/drawable-xhdpi/ic_brush_size_med.png b/res/drawable-xhdpi/ic_brush_size_med.png Binary files differnew file mode 100644 index 000000000..37a0f6a2c --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_med.png diff --git a/res/drawable-xhdpi/ic_brush_size_med_sel.png b/res/drawable-xhdpi/ic_brush_size_med_sel.png Binary files differnew file mode 100644 index 000000000..44da98afa --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_med_sel.png diff --git a/res/drawable-xhdpi/ic_brush_size_sm.png b/res/drawable-xhdpi/ic_brush_size_sm.png Binary files differnew file mode 100644 index 000000000..d46aba34e --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_sm.png diff --git a/res/drawable-xhdpi/ic_brush_size_sm_sel.png b/res/drawable-xhdpi/ic_brush_size_sm_sel.png Binary files differnew file mode 100644 index 000000000..95fc19810 --- /dev/null +++ b/res/drawable-xhdpi/ic_brush_size_sm_sel.png diff --git a/res/drawable-xhdpi/ic_tp_bokeh.png b/res/drawable-xhdpi/ic_tp_bokeh.png Binary files differnew file mode 100644 index 000000000..b1d9cc93f --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_bokeh.png diff --git a/res/drawable-xhdpi/ic_tp_fusion.png b/res/drawable-xhdpi/ic_tp_fusion.png Binary files differnew file mode 100644 index 000000000..075eaaf56 --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_fusion.png diff --git a/res/drawable-xhdpi/ic_tp_halo.png b/res/drawable-xhdpi/ic_tp_halo.png Binary files differnew file mode 100644 index 000000000..30eb7d991 --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_halo.png diff --git a/res/drawable-xhdpi/ic_tp_motion_blur.png b/res/drawable-xhdpi/ic_tp_motion_blur.png Binary files differnew file mode 100644 index 000000000..ba0e1737c --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_motion_blur.png diff --git a/res/drawable-xhdpi/ic_tp_normal.png b/res/drawable-xhdpi/ic_tp_normal.png Binary files differnew file mode 100644 index 000000000..de667bf3a --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_normal.png diff --git a/res/drawable-xhdpi/ic_tp_sketch.png b/res/drawable-xhdpi/ic_tp_sketch.png Binary files differnew file mode 100644 index 000000000..fa014348e --- /dev/null +++ b/res/drawable-xhdpi/ic_tp_sketch.png diff --git a/res/drawable-xhdpi/trueportrait.png b/res/drawable-xhdpi/trueportrait.png Binary files differnew file mode 100644 index 000000000..17f1ba425 --- /dev/null +++ b/res/drawable-xhdpi/trueportrait.png diff --git a/res/drawable-xhdpi/trueportrait_disabled.png b/res/drawable-xhdpi/trueportrait_disabled.png Binary files differnew file mode 100644 index 000000000..c0858e1f7 --- /dev/null +++ b/res/drawable-xhdpi/trueportrait_disabled.png diff --git a/res/drawable-xhdpi/trueportrait_select.png b/res/drawable-xhdpi/trueportrait_select.png Binary files differnew file mode 100644 index 000000000..a334b2ad9 --- /dev/null +++ b/res/drawable-xhdpi/trueportrait_select.png diff --git a/res/drawable-xxhdpi/btn_tp_help.png b/res/drawable-xxhdpi/btn_tp_help.png Binary files differnew file mode 100644 index 000000000..95732571e --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_help.png diff --git a/res/drawable-xxhdpi/btn_tp_help_sel.png b/res/drawable-xxhdpi/btn_tp_help_sel.png Binary files differnew file mode 100644 index 000000000..554774cf9 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_help_sel.png diff --git a/res/drawable-xxhdpi/btn_tp_sel_bg.png b/res/drawable-xxhdpi/btn_tp_sel_bg.png Binary files differnew file mode 100644 index 000000000..8d6eea054 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_sel_bg.png diff --git a/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png b/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png Binary files differnew file mode 100644 index 000000000..f0e53af56 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_sel_bg_sel.png diff --git a/res/drawable-xxhdpi/btn_tp_touchup.png b/res/drawable-xxhdpi/btn_tp_touchup.png Binary files differnew file mode 100644 index 000000000..4113cb796 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_touchup.png diff --git a/res/drawable-xxhdpi/btn_tp_touchup_sel.png b/res/drawable-xxhdpi/btn_tp_touchup_sel.png Binary files differnew file mode 100644 index 000000000..52acfba68 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_touchup_sel.png diff --git a/res/drawable-xxhdpi/btn_tp_undo.png b/res/drawable-xxhdpi/btn_tp_undo.png Binary files differnew file mode 100644 index 000000000..448608d0b --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_undo.png diff --git a/res/drawable-xxhdpi/btn_tp_undo_disabled.png b/res/drawable-xxhdpi/btn_tp_undo_disabled.png Binary files differnew file mode 100644 index 000000000..71270ae31 --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_undo_disabled.png diff --git a/res/drawable-xxhdpi/btn_tp_undo_sel.png b/res/drawable-xxhdpi/btn_tp_undo_sel.png Binary files differnew file mode 100644 index 000000000..25a20987d --- /dev/null +++ b/res/drawable-xxhdpi/btn_tp_undo_sel.png diff --git a/res/drawable-xxhdpi/ic_brush_size_large.png b/res/drawable-xxhdpi/ic_brush_size_large.png Binary files differnew file mode 100644 index 000000000..6b91b53c8 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_large.png diff --git a/res/drawable-xxhdpi/ic_brush_size_large_sel.png b/res/drawable-xxhdpi/ic_brush_size_large_sel.png Binary files differnew file mode 100644 index 000000000..9371f3062 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_large_sel.png diff --git a/res/drawable-xxhdpi/ic_brush_size_med.png b/res/drawable-xxhdpi/ic_brush_size_med.png Binary files differnew file mode 100644 index 000000000..8a7e9e1a8 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_med.png diff --git a/res/drawable-xxhdpi/ic_brush_size_med_sel.png b/res/drawable-xxhdpi/ic_brush_size_med_sel.png Binary files differnew file mode 100644 index 000000000..d02b0c087 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_med_sel.png diff --git a/res/drawable-xxhdpi/ic_brush_size_sm.png b/res/drawable-xxhdpi/ic_brush_size_sm.png Binary files differnew file mode 100644 index 000000000..5757c9581 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_sm.png diff --git a/res/drawable-xxhdpi/ic_brush_size_sm_sel.png b/res/drawable-xxhdpi/ic_brush_size_sm_sel.png Binary files differnew file mode 100644 index 000000000..28829b209 --- /dev/null +++ b/res/drawable-xxhdpi/ic_brush_size_sm_sel.png diff --git a/res/drawable-xxhdpi/ic_tp_bokeh.png b/res/drawable-xxhdpi/ic_tp_bokeh.png Binary files differnew file mode 100644 index 000000000..598e7d42e --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_bokeh.png diff --git a/res/drawable-xxhdpi/ic_tp_fusion.png b/res/drawable-xxhdpi/ic_tp_fusion.png Binary files differnew file mode 100644 index 000000000..59daba460 --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_fusion.png diff --git a/res/drawable-xxhdpi/ic_tp_halo.png b/res/drawable-xxhdpi/ic_tp_halo.png Binary files differnew file mode 100644 index 000000000..2f608765c --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_halo.png diff --git a/res/drawable-xxhdpi/ic_tp_motion_blur.png b/res/drawable-xxhdpi/ic_tp_motion_blur.png Binary files differnew file mode 100644 index 000000000..2b88c9bf0 --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_motion_blur.png diff --git a/res/drawable-xxhdpi/ic_tp_normal.png b/res/drawable-xxhdpi/ic_tp_normal.png Binary files differnew file mode 100644 index 000000000..2a153ff4c --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_normal.png diff --git a/res/drawable-xxhdpi/ic_tp_sketch.png b/res/drawable-xxhdpi/ic_tp_sketch.png Binary files differnew file mode 100644 index 000000000..cbc7d7b5a --- /dev/null +++ b/res/drawable-xxhdpi/ic_tp_sketch.png diff --git a/res/drawable-xxhdpi/trueportrait.png b/res/drawable-xxhdpi/trueportrait.png Binary files differnew file mode 100644 index 000000000..3b46c8086 --- /dev/null +++ b/res/drawable-xxhdpi/trueportrait.png diff --git a/res/drawable-xxhdpi/trueportrait_disabled.png b/res/drawable-xxhdpi/trueportrait_disabled.png Binary files differnew file mode 100644 index 000000000..93d4926ff --- /dev/null +++ b/res/drawable-xxhdpi/trueportrait_disabled.png diff --git a/res/drawable-xxhdpi/trueportrait_select.png b/res/drawable-xxhdpi/trueportrait_select.png Binary files differnew file mode 100644 index 000000000..d5c3b5d9d --- /dev/null +++ b/res/drawable-xxhdpi/trueportrait_select.png 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 Binary files differnew file mode 100644 index 000000000..a85e96651 --- /dev/null +++ b/res/raw/sketch_bm.jpg 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()); } } |
