[WPP2] Image Preview Fragment
Created a new preview fragment for previewing static image wallpaper.
This is the first implementation. Further refining work is needed.
Test: Manual
Bug: 242908637
Change-Id: I50828cde9f5ed458db0b51905442d3196e0ab70a
diff --git a/Android.bp b/Android.bp
index dbffb77..4827264 100644
--- a/Android.bp
+++ b/Android.bp
@@ -109,6 +109,7 @@
static_libs: [
"renderscript_toolkit",
"wallpaper-common-deps",
+ "monet",
],
jni_libs: [
diff --git a/res/color/wallpaper_control_button_ic_color_tint.xml b/res/color/wallpaper_control_button_ic_color_tint.xml
new file mode 100644
index 0000000..534a5e5
--- /dev/null
+++ b/res/color/wallpaper_control_button_ic_color_tint.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:state_checked="true" android:color="?androidprv:attr/textColorOnAccent" />
+ <item android:state_checked="false" android:color="?android:textColorTertiary" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/duo_tabs_button_background.xml b/res/drawable/duo_tabs_button_background.xml
new file mode 100644
index 0000000..b06f36f
--- /dev/null
+++ b/res/drawable/duo_tabs_button_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/duo_tabs_button_corner_radius" />
+ <solid android:color="?android:colorControlHighlight" />
+ </shape>
+ </item>
+
+ <item android:drawable="@drawable/duo_tabs_button_background_base" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/duo_tabs_button_background_base.xml b/res/drawable/duo_tabs_button_background_base.xml
new file mode 100644
index 0000000..cc716c2
--- /dev/null
+++ b/res/drawable/duo_tabs_button_background_base.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/duo_tabs_button_corner_radius" />
+ <solid android:color="?androidprv:attr/colorSurface" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/duo_tabs_button_indicator_background.xml b/res/drawable/duo_tabs_button_indicator_background.xml
new file mode 100644
index 0000000..86841c5
--- /dev/null
+++ b/res/drawable/duo_tabs_button_indicator_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/duo_tabs_button_corner_radius" />
+ <solid android:color="?android:colorControlHighlight" />
+ </shape>
+ </item>
+
+ <item android:drawable="@drawable/duo_tabs_button_indicator_background_base" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/duo_tabs_button_indicator_background_base.xml b/res/drawable/duo_tabs_button_indicator_background_base.xml
new file mode 100644
index 0000000..61c9080
--- /dev/null
+++ b/res/drawable/duo_tabs_button_indicator_background_base.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/duo_tabs_button_corner_radius" />
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/duo_tabs_divider.xml b/res/drawable/duo_tabs_divider.xml
new file mode 100644
index 0000000..8325048
--- /dev/null
+++ b/res/drawable/duo_tabs_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <size
+ android:height="0dp"
+ android:width="@dimen/duo_tabs_divider_space" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/ic_effect.xml b/res/drawable/ic_effect.xml
new file mode 100644
index 0000000..fe4acba
--- /dev/null
+++ b/res/drawable/ic_effect.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2022 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/wallpaper_control_icon_size"
+ android:height="@dimen/wallpaper_control_icon_size"
+ android:viewportHeight="@dimen/wallpaper_control_icon_viewport_size"
+ android:viewportWidth="@dimen/wallpaper_control_icon_viewport_size"
+ android:tintMode="multiply"
+ android:tint="@color/wallpaper_control_button_ic_color_tint">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19.6352 8.72727L20.9984 5.72648L24 4.36364L20.9984 3.0008L19.6352 0L18.272 3.0008L15.2704 4.36364L18.272 5.72648L19.6352 8.72727ZM11.456 9.27113L8.7296 3.26953L6.0032 9.27113L0 11.9968L6.0032 14.7225L8.7296 20.7241L11.456 14.7225L17.4592 11.9968L11.456 9.27113ZM19.6352 15.2727L18.272 18.2735L15.2704 19.6364L18.272 20.9992L19.6352 24L20.9984 20.9992L24 19.6364L20.9984 18.2735L19.6352 15.2727Z" />
+</vector>
diff --git a/res/drawable/ic_info.xml b/res/drawable/ic_info.xml
new file mode 100644
index 0000000..1cbabe7
--- /dev/null
+++ b/res/drawable/ic_info.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2022 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/wallpaper_control_icon_size"
+ android:height="@dimen/wallpaper_control_icon_size"
+ android:viewportWidth="@dimen/wallpaper_control_icon_viewport_size"
+ android:viewportHeight="@dimen/wallpaper_control_icon_viewport_size"
+ android:tintMode="multiply"
+ android:tint="@color/wallpaper_control_button_ic_color_tint">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
+</vector>
diff --git a/res/drawable/set_wallpaper_button_background.xml b/res/drawable/set_wallpaper_button_background.xml
new file mode 100644
index 0000000..a19a3fc
--- /dev/null
+++ b/res/drawable/set_wallpaper_button_background.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/set_wallpaper_button_corner_radius" />
+ <padding
+ android:left="@dimen/set_wallpaper_button_horizontal_padding"
+ android:top="@dimen/set_wallpaper_button_vertical_padding"
+ android:right="@dimen/set_wallpaper_button_horizontal_padding"
+ android:bottom="@dimen/set_wallpaper_button_vertical_padding" />
+ <solid android:color="?android:colorControlHighlight" />
+ </shape>
+ </item>
+
+ <item android:drawable="@drawable/set_wallpaper_button_background_base" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/set_wallpaper_button_background_base.xml b/res/drawable/set_wallpaper_button_background_base.xml
new file mode 100644
index 0000000..027b06c
--- /dev/null
+++ b/res/drawable/set_wallpaper_button_background_base.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/set_wallpaper_button_corner_radius" />
+ <padding
+ android:left="@dimen/set_wallpaper_button_horizontal_padding"
+ android:top="@dimen/set_wallpaper_button_vertical_padding"
+ android:right="@dimen/set_wallpaper_button_horizontal_padding"
+ android:bottom="@dimen/set_wallpaper_button_vertical_padding" />
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_background.xml b/res/drawable/wallpaper_control_button_background.xml
new file mode 100644
index 0000000..e3954dc
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true"
+ android:drawable="@drawable/wallpaper_control_button_on_background" />
+ <item android:drawable="@drawable/wallpaper_control_button_off_background" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_effect.xml b/res/drawable/wallpaper_control_button_effect.xml
new file mode 100644
index 0000000..a3c975b
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_effect.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/wallpaper_control_button_background" />
+ <item android:drawable="@drawable/ic_effect" />
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_group_divider.xml b/res/drawable/wallpaper_control_button_group_divider.xml
new file mode 100644
index 0000000..b8f115c
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_group_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <size
+ android:height="@dimen/wallpaper_control_button_group_divider_space"
+ android:width="0dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_info.xml b/res/drawable/wallpaper_control_button_info.xml
new file mode 100644
index 0000000..c3954c1
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_info.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/wallpaper_control_button_background" />
+ <item android:drawable="@drawable/ic_info" />
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_off_background.xml b/res/drawable/wallpaper_control_button_off_background.xml
new file mode 100644
index 0000000..7c0b1bc
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_off_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval">
+ <padding
+ android:bottom="@dimen/wallpaper_control_button_padding"
+ android:left="@dimen/wallpaper_control_button_padding"
+ android:right="@dimen/wallpaper_control_button_padding"
+ android:top="@dimen/wallpaper_control_button_padding" />
+ <solid android:color="?android:colorControlHighlight" />
+ </shape>
+ </item>
+
+ <item android:drawable="@drawable/wallpaper_control_button_off_background_base" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_off_background_base.xml b/res/drawable/wallpaper_control_button_off_background_base.xml
new file mode 100644
index 0000000..97294e5
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_off_background_base.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="oval">
+ <padding
+ android:left="@dimen/wallpaper_control_button_padding"
+ android:right="@dimen/wallpaper_control_button_padding"
+ android:top="@dimen/wallpaper_control_button_padding"
+ android:bottom="@dimen/wallpaper_control_button_padding"/>
+ <solid android:color="?androidprv:attr/colorSurface"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_on_background.xml b/res/drawable/wallpaper_control_button_on_background.xml
new file mode 100644
index 0000000..3e35d09
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_on_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval">
+ <padding
+ android:bottom="@dimen/wallpaper_control_button_padding"
+ android:left="@dimen/wallpaper_control_button_padding"
+ android:right="@dimen/wallpaper_control_button_padding"
+ android:top="@dimen/wallpaper_control_button_padding" />
+ <solid android:color="?android:colorControlHighlight" />
+ </shape>
+ </item>
+
+ <item android:drawable="@drawable/wallpaper_control_button_on_background_base" />
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/wallpaper_control_button_on_background_base.xml b/res/drawable/wallpaper_control_button_on_background_base.xml
new file mode 100644
index 0000000..e0f4d78
--- /dev/null
+++ b/res/drawable/wallpaper_control_button_on_background_base.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="oval">
+ <padding
+ android:left="@dimen/wallpaper_control_button_padding"
+ android:right="@dimen/wallpaper_control_button_padding"
+ android:top="@dimen/wallpaper_control_button_padding"
+ android:bottom="@dimen/wallpaper_control_button_padding"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/duo_tabs.xml b/res/layout/duo_tabs.xml
new file mode 100644
index 0000000..5a25376
--- /dev/null
+++ b/res/layout/duo_tabs.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:divider="@drawable/duo_tabs_divider"
+ android:orientation="horizontal"
+ android:showDividers="middle">
+
+ <Button
+ android:id="@+id/tab_primary"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/separated_tabs_height"
+ android:layout_weight="1"
+ android:background="@drawable/duo_tabs_button_background"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/tab_secondary"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/separated_tabs_height"
+ android:layout_weight="1"
+ android:background="@drawable/duo_tabs_button_background"
+ android:gravity="center" />
+</LinearLayout>
diff --git a/res/layout/fragment_image_preview_2.xml b/res/layout/fragment_image_preview_2.xml
new file mode 100644
index 0000000..7ffe43f
--- /dev/null
+++ b/res/layout/fragment_image_preview_2.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.wallpaper.picker.TouchForwardingLayout2
+ android:id="@+id/touch_forwarding_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"/>
+
+ <include layout="@layout/wallpaper_preview" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:fitsSystemWindows="true">
+
+ <Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ app:layout_constraintEnd_toStartOf="@+id/button_set_wallpaper_container"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <FrameLayout
+ android:id="@+id/button_set_wallpaper_container"
+ android:layout_width="wrap_content"
+ android:layout_height="?android:attr/actionBarSize"
+ android:layout_marginEnd="@dimen/set_wallpaper_button_margin_end"
+ android:layout_marginBottom="@dimen/set_wallpaper_button_margin_bottom"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <Button
+ android:id="@+id/button_set_wallpaper"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/set_wallpaper_button_background"
+ android:gravity="center"
+ android:text="@string/set_wallpaper_button_text"
+ android:textColor="?androidprv:attr/textColorOnAccent" />
+ </FrameLayout>
+
+ <com.android.wallpaper.widget.WallpaperControlButtonGroup
+ android:id="@+id/wallpaper_control_button_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/wallpaper_control_button_group_margin_end"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button_set_wallpaper_container" />
+
+ <com.android.wallpaper.widget.DuoTabs
+ android:id="@+id/overlay_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/full_preview_page_tabs_horizontal_padding"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</FrameLayout>
diff --git a/res/layout/wallpaper_control_button_group.xml b/res/layout/wallpaper_control_button_group.xml
new file mode 100644
index 0000000..1b749f0
--- /dev/null
+++ b/res/layout/wallpaper_control_button_group.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_control_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="@drawable/wallpaper_control_button_group_divider"
+ android:showDividers="middle">
+
+ <ToggleButton
+ android:id="@+id/effects_button"
+ android:layout_width="@dimen/wallpaper_control_button_size"
+ android:layout_height="@dimen/wallpaper_control_button_size"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/tab_effects"
+ android:foreground="@drawable/wallpaper_control_button_effect"
+ android:textOff=""
+ android:textOn=""
+ android:visibility="gone" />
+
+ <ToggleButton
+ android:id="@+id/information_button"
+ android:layout_width="@dimen/wallpaper_control_button_size"
+ android:layout_height="@dimen/wallpaper_control_button_size"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/tab_info"
+ android:foreground="@drawable/wallpaper_control_button_info"
+ android:textOff=""
+ android:textOn=""
+ android:visibility="gone" />
+</LinearLayout>
+
diff --git a/res/layout/wallpaper_preview.xml b/res/layout/wallpaper_preview.xml
new file mode 100644
index 0000000..f7dbf64
--- /dev/null
+++ b/res/layout/wallpaper_preview.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2022 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/wallpaper_preview_card_content_description">
+
+ <SurfaceView
+ android:id="@+id/wallpaper_surface"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <SurfaceView
+ android:id="@+id/wallpaper_surface_cinematic"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <SurfaceView
+ android:id="@+id/workspace_surface"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="noHideDescendants" />
+
+ <FrameLayout
+ android:id="@+id/lock_screen_preview_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="noHideDescendants" />
+
+ <androidx.core.widget.ContentLoadingProgressBar
+ android:id="@+id/wallpaper_preview_spinner"
+ style="?android:progressBarStyleLarge"
+ android:background="@android:color/transparent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+</FrameLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 023aba4..9e0001f 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -238,4 +238,26 @@
<dimen name="wallpaper_effect_failed_container_margin_top">24dp</dimen>
<dimen name="wallpaper_effect_failed_button_size">16sp</dimen>
+ <!-- Clipping of the home screen overlay -->
+ <dimen name="home_screen_overlay_top_clipping">100dp</dimen>
+ <dimen name="home_screen_overlay_bottom_clipping">40dp</dimen>
+
+ <!-- Set wallpaper button -->
+ <dimen name="set_wallpaper_button_horizontal_padding">18dp</dimen>
+ <dimen name="set_wallpaper_button_vertical_padding">10dp</dimen>
+ <dimen name="set_wallpaper_button_corner_radius">20dp</dimen>
+ <dimen name="set_wallpaper_button_margin_end">20dp</dimen>
+ <dimen name="set_wallpaper_button_margin_bottom">24dp</dimen>
+
+ <!-- Wallpaper control button group -->
+ <dimen name="wallpaper_control_button_group_divider_space">12dp</dimen>
+ <dimen name="wallpaper_control_button_group_margin_end">18dp</dimen>
+ <dimen name="wallpaper_control_button_padding">12dp</dimen>
+ <dimen name="wallpaper_control_button_size">48dp</dimen>
+ <dimen name="wallpaper_control_icon_size">24dp</dimen>
+ <item name="wallpaper_control_icon_viewport_size" format="float" type="dimen">24</item>
+
+ <!-- Duo tabs -->
+ <dimen name="duo_tabs_button_corner_radius">12dp</dimen>
+ <dimen name="duo_tabs_divider_space">8dp</dimen>
</resources>
diff --git a/src/com/android/wallpaper/module/WallpaperSetter2.java b/src/com/android/wallpaper/module/WallpaperSetter2.java
new file mode 100644
index 0000000..e07ba19
--- /dev/null
+++ b/src/com/android/wallpaper/module/WallpaperSetter2.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.module;
+
+import static android.app.WallpaperManager.FLAG_LOCK;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.util.Log;
+import android.view.Display;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.Lifecycle.Event;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.asset.Asset;
+import com.android.wallpaper.model.LiveWallpaperInfo;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.UserEventLogger.WallpaperSetFailureReason;
+import com.android.wallpaper.module.WallpaperPersister.Destination;
+import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
+import com.android.wallpaper.picker.SetWallpaperDialogFragment;
+import com.android.wallpaper.picker.SetWallpaperDialogFragment.Listener;
+import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.ThrowableAnalyzer;
+import com.android.wallpaper.util.WallpaperCropUtils;
+
+import com.bumptech.glide.Glide;
+
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * Helper class used to set the current wallpaper. It handles showing the destination request dialog
+ * and actually setting the wallpaper on a given destination.
+ * It is expected to be instantiated within a Fragment or Activity, and {@link #cleanUp()} should
+ * be called from its owner's onDestroy method (or equivalent).
+ * TODO b/256819974 This is a duplicate of WallpaperSetter and should be removed after
+ * WallpaperSetter in the branch of tm-qpr-dev is synced with master.
+ */
+public class WallpaperSetter2 {
+
+ private static final String TAG = "WallpaperSetter2";
+ private static final String PROGRESS_DIALOG_NO_TITLE = null;
+ private static final boolean PROGRESS_DIALOG_INDETERMINATE = true;
+
+ private static final int UNUSED_REQUEST_CODE = 1;
+ private static final String TAG_SET_WALLPAPER_DIALOG_FRAGMENT = "set_wallpaper_dialog";
+
+ private final WallpaperPersister mWallpaperPersister;
+ private final WallpaperPreferences mPreferences;
+ private final boolean mTestingModeEnabled;
+ private final UserEventLogger mUserEventLogger;
+ private ProgressDialog mProgressDialog;
+ private Optional<Integer> mCurrentScreenOrientation = Optional.empty();
+
+ public WallpaperSetter2(WallpaperPersister wallpaperPersister,
+ WallpaperPreferences preferences, UserEventLogger userEventLogger,
+ boolean isTestingModeEnabled) {
+ mTestingModeEnabled = isTestingModeEnabled;
+ mWallpaperPersister = wallpaperPersister;
+ mPreferences = preferences;
+ mUserEventLogger = userEventLogger;
+ }
+
+ /**
+ * Sets current wallpaper to the device with the minimum scale to fit the screen size.
+ *
+ * @param containerActivity main Activity that owns the current fragment
+ * @param wallpaper info for the actual wallpaper to set
+ * @param destination the wallpaper destination i.e. home vs. lockscreen vs. both.
+ * @param callback optional callback to be notified when the wallpaper is set.
+ */
+ public void setCurrentWallpaper(Activity containerActivity, WallpaperInfo wallpaper,
+ @Destination final int destination,
+ @Nullable SetWallpaperCallback callback) {
+ Asset wallpaperAsset = wallpaper.getAsset(containerActivity.getApplicationContext());
+ wallpaperAsset.decodeRawDimensions(containerActivity, dimensions -> {
+ if (dimensions == null) {
+ Log.e(TAG, "Raw wallpaper's dimensions are null");
+ return;
+ }
+
+ Display defaultDisplay = containerActivity.getWindowManager().getDefaultDisplay();
+ Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(defaultDisplay);
+ Rect visibleRawWallpaperRect =
+ WallpaperCropUtils.calculateVisibleRect(dimensions, screenSize);
+ float wallpaperScale = WallpaperCropUtils.calculateMinZoom(dimensions, screenSize);
+ Rect cropRect = WallpaperCropUtils.calculateCropRect(
+ containerActivity.getApplicationContext(), defaultDisplay,
+ dimensions, visibleRawWallpaperRect, wallpaperScale);
+
+ setCurrentWallpaper(containerActivity, wallpaper, wallpaperAsset, destination,
+ wallpaperScale, cropRect, null, callback);
+ });
+ }
+
+ /**
+ * Sets current wallpaper to the device based on current zoom and scroll state.
+ *
+ * @param containerActivity main Activity that owns the current fragment
+ * @param wallpaper info for the actual wallpaper to set
+ * @param wallpaperAsset Wallpaper asset from which to retrieve image data.
+ * @param destination The wallpaper destination i.e. home vs. lockscreen vs. both.
+ * @param wallpaperScale Scaling factor applied to the source image before setting the
+ * wallpaper to the device.
+ * @param cropRect Desired crop area of the wallpaper in post-scale units. If null,
+ * then the
+ * wallpaper image will be set without any scaling or cropping.
+ * @param callback optional callback to be notified when the wallpaper is set.
+ */
+ public void setCurrentWallpaper(Activity containerActivity, WallpaperInfo wallpaper,
+ @Nullable Asset wallpaperAsset, @Destination final int destination,
+ float wallpaperScale, @Nullable Rect cropRect, WallpaperColors wallpaperColors,
+ @Nullable SetWallpaperCallback callback) {
+ if (wallpaper instanceof LiveWallpaperInfo) {
+ setCurrentLiveWallpaper(containerActivity, (LiveWallpaperInfo) wallpaper, destination,
+ wallpaperColors, callback);
+ return;
+ }
+ mPreferences.setPendingWallpaperSetStatus(
+ WallpaperPreferences.WALLPAPER_SET_PENDING);
+
+ // Save current screen rotation so we can temporarily disable rotation while setting the
+ // wallpaper and restore after setting the wallpaper finishes.
+ saveAndLockScreenOrientationIfNeeded(containerActivity);
+
+ // Clear MosaicView tiles and Glide's cache and pools to reclaim memory for final cropped
+ // bitmap.
+ Glide.get(containerActivity).clearMemory();
+
+ // ProgressDialog endlessly updates the UI thread, keeping it from going idle which
+ // therefore
+ // causes Espresso to hang once the dialog is shown.
+ if (!mTestingModeEnabled && !containerActivity.isFinishing()) {
+ int themeResId = (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
+ ? R.style.ProgressDialogThemePreL : R.style.LightDialogTheme;
+ mProgressDialog = new ProgressDialog(containerActivity, themeResId);
+
+ mProgressDialog.setTitle(PROGRESS_DIALOG_NO_TITLE);
+ mProgressDialog.setMessage(containerActivity.getString(
+ R.string.set_wallpaper_progress_message));
+ mProgressDialog.setIndeterminate(PROGRESS_DIALOG_INDETERMINATE);
+ if (containerActivity instanceof LifecycleOwner) {
+ ((LifecycleOwner) containerActivity).getLifecycle().addObserver(
+ new LifecycleEventObserver() {
+ @Override
+ public void onStateChanged(@NonNull LifecycleOwner source,
+ @NonNull Event event) {
+ if (event == Event.ON_DESTROY) {
+ if (mProgressDialog != null) {
+ mProgressDialog.dismiss();
+ mProgressDialog = null;
+ }
+ }
+ }
+ });
+ }
+ mProgressDialog.show();
+ }
+
+ mWallpaperPersister.setIndividualWallpaper(
+ wallpaper, wallpaperAsset, cropRect,
+ wallpaperScale, destination, new SetWallpaperCallback() {
+ @Override
+ public void onSuccess(WallpaperInfo wallpaperInfo) {
+ onWallpaperApplied(wallpaper, containerActivity);
+ if (callback != null) {
+ callback.onSuccess(wallpaper);
+ }
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ onWallpaperApplyError(throwable, containerActivity);
+ if (callback != null) {
+ callback.onError(throwable);
+ }
+ }
+ });
+ }
+
+ private void setCurrentLiveWallpaper(Activity activity, LiveWallpaperInfo wallpaper,
+ @Destination final int destination, WallpaperColors colors,
+ @Nullable SetWallpaperCallback callback) {
+ try {
+ // Save current screen rotation so we can temporarily disable rotation while setting the
+ // wallpaper and restore after setting the wallpaper finishes.
+ saveAndLockScreenOrientationIfNeeded(activity);
+
+ if (destination == WallpaperPersister.DEST_LOCK_SCREEN) {
+ throw new IllegalArgumentException(
+ "Live wallpaper cannot be applied on lock screen only");
+ }
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(activity);
+ wallpaperManager.setWallpaperComponentWithFlags(
+ wallpaper.getWallpaperComponent().getComponent(),
+ WallpaperPersister.destinationToFlags(destination));
+ wallpaperManager.setWallpaperOffsetSteps(0.5f /* xStep */, 0.0f /* yStep */);
+ wallpaperManager.setWallpaperOffsets(
+ activity.getWindow().getDecorView().getRootView().getWindowToken(),
+ 0.5f /* xOffset */, 0.0f /* yOffset */);
+ if (destination == WallpaperPersister.DEST_BOTH) {
+ wallpaperManager.clear(FLAG_LOCK);
+ }
+ mPreferences.storeLatestHomeWallpaper(wallpaper.getWallpaperId(), wallpaper, colors);
+ onWallpaperApplied(wallpaper, activity);
+ if (callback != null) {
+ callback.onSuccess(wallpaper);
+ }
+ } catch (RuntimeException | IOException e) {
+ onWallpaperApplyError(e, activity);
+ if (callback != null) {
+ callback.onError(e);
+ }
+ }
+ }
+
+ /**
+ * Sets current live wallpaper to the device (restore case)
+ *
+ * @param context The context for initiating wallpaper manager
+ * @param wallpaper Information for the actual wallpaper to set
+ * @param destination The wallpaper destination i.e. home vs. lockscreen vs. both
+ * @param colors The {@link WallpaperColors} for placeholder of quickswitching
+ * @param callback Optional callback to be notified when the wallpaper is set.
+ */
+ public void setCurrentLiveWallpaper(Context context, LiveWallpaperInfo wallpaper,
+ @Destination final int destination, @Nullable WallpaperColors colors,
+ @Nullable SetWallpaperCallback callback) {
+ try {
+ if (destination == WallpaperPersister.DEST_LOCK_SCREEN) {
+ throw new IllegalArgumentException(
+ "Live wallpaper cannot be applied on lock screen only");
+ }
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
+ wallpaperManager.setWallpaperComponentWithFlags(
+ wallpaper.getWallpaperComponent().getComponent(),
+ WallpaperPersister.destinationToFlags(destination));
+ if (destination == WallpaperPersister.DEST_BOTH) {
+ wallpaperManager.clear(FLAG_LOCK);
+ }
+ mPreferences.storeLatestHomeWallpaper(wallpaper.getWallpaperId(), wallpaper,
+ colors != null ? colors :
+ WallpaperColors.fromBitmap(wallpaper.getThumbAsset(context)
+ .getLowResBitmap(context)));
+ // Not call onWallpaperApplied() as no UI is presented.
+ if (callback != null) {
+ callback.onSuccess(wallpaper);
+ }
+ } catch (RuntimeException | IOException e) {
+ // Not call onWallpaperApplyError() as no UI is presented.
+ if (callback != null) {
+ callback.onError(e);
+ }
+ }
+ }
+
+ private void onWallpaperApplied(WallpaperInfo wallpaper, Activity containerActivity) {
+ mUserEventLogger.logWallpaperSet(
+ wallpaper.getCollectionId(containerActivity),
+ wallpaper.getWallpaperId(), wallpaper.getEffectNames());
+ mPreferences.setPendingWallpaperSetStatus(
+ WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
+ mUserEventLogger.logWallpaperSetResult(
+ UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS);
+ cleanUp();
+ restoreScreenOrientationIfNeeded(containerActivity);
+ }
+
+ private void onWallpaperApplyError(Throwable throwable, Activity containerActivity) {
+ mPreferences.setPendingWallpaperSetStatus(
+ WallpaperPreferences.WALLPAPER_SET_NOT_PENDING);
+ mUserEventLogger.logWallpaperSetResult(
+ UserEventLogger.WALLPAPER_SET_RESULT_FAILURE);
+ @WallpaperSetFailureReason int failureReason = ThrowableAnalyzer.isOOM(
+ throwable)
+ ? UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OOM
+ : UserEventLogger.WALLPAPER_SET_FAILURE_REASON_OTHER;
+ mUserEventLogger.logWallpaperSetFailureReason(failureReason);
+
+ cleanUp();
+ restoreScreenOrientationIfNeeded(containerActivity);
+ }
+
+ /**
+ * Call this method to clean up this instance's state.
+ */
+ public void cleanUp() {
+ if (mProgressDialog != null) {
+ mProgressDialog.dismiss();
+ mProgressDialog = null;
+ }
+ }
+
+ /**
+ * Show a dialog asking the user for the Wallpaper's destination
+ * (eg, "Home screen", "Lock Screen")
+ *
+ * @param isLiveWallpaper whether the wallpaper that we want to set is a live wallpaper.
+ * @param listener {@link Listener} that will receive the response.
+ * @see Destination
+ */
+ public void requestDestination(Activity activity, FragmentManager fragmentManager,
+ Listener listener, boolean isLiveWallpaper) {
+ requestDestination(activity, fragmentManager, R.string.set_wallpaper_dialog_message,
+ listener, isLiveWallpaper);
+ }
+
+ /**
+ * Show a dialog asking the user for the Wallpaper's destination
+ * (eg, "Home screen", "Lock Screen")
+ *
+ * @param isLiveWallpaper whether the wallpaper that we want to set is a live wallpaper.
+ * @param listener {@link Listener} that will receive the response.
+ * @param titleResId title for the dialog
+ * @see Destination
+ */
+ public void requestDestination(Activity activity, FragmentManager fragmentManager,
+ @StringRes int titleResId, Listener listener, boolean isLiveWallpaper) {
+ saveAndLockScreenOrientationIfNeeded(activity);
+ Listener listenerWrapper = new Listener() {
+ @Override
+ public void onSet(int destination) {
+ if (listener != null) {
+ listener.onSet(destination);
+ }
+ }
+
+ @Override
+ public void onDialogDismissed(boolean withItemSelected) {
+ if (!withItemSelected) {
+ restoreScreenOrientationIfNeeded(activity);
+ }
+ if (listener != null) {
+ listener.onDialogDismissed(withItemSelected);
+ }
+ }
+ };
+
+ WallpaperStatusChecker wallpaperStatusChecker =
+ InjectorProvider.getInjector().getWallpaperStatusChecker();
+ boolean isLiveWallpaperSet =
+ WallpaperManager.getInstance(activity).getWallpaperInfo() != null;
+ // Alternative of ag/15567276
+ boolean isBuiltIn = !isLiveWallpaperSet
+ && !wallpaperStatusChecker.isHomeStaticWallpaperSet(activity);
+
+ SetWallpaperDialogFragment setWallpaperDialog = new SetWallpaperDialogFragment();
+ setWallpaperDialog.setTitleResId(titleResId);
+ setWallpaperDialog.setListener(listenerWrapper);
+ if ((isLiveWallpaperSet || isBuiltIn)
+ && !wallpaperStatusChecker.isLockWallpaperSet(activity)) {
+ if (isLiveWallpaper) {
+ // If lock wallpaper is live and we're setting a live wallpaper, we can only
+ // set it to both, so bypass the dialog.
+ listener.onSet(WallpaperPersister.DEST_BOTH);
+ restoreScreenOrientationIfNeeded(activity);
+ return;
+ }
+ // if the lock wallpaper is a live wallpaper, we cannot set a home-only static one
+ setWallpaperDialog.setHomeOptionAvailable(false);
+ }
+ if (isLiveWallpaper) {
+ setWallpaperDialog.setLockOptionAvailable(false);
+ }
+ setWallpaperDialog.show(fragmentManager, TAG_SET_WALLPAPER_DIALOG_FRAGMENT);
+ }
+
+ private void saveAndLockScreenOrientationIfNeeded(Activity activity) {
+ if (!mCurrentScreenOrientation.isPresent()) {
+ mCurrentScreenOrientation = Optional.of(activity.getRequestedOrientation());
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+ }
+ }
+
+ private void restoreScreenOrientationIfNeeded(Activity activity) {
+ mCurrentScreenOrientation.ifPresent(orientation -> {
+ if (activity.getRequestedOrientation() != orientation) {
+ activity.setRequestedOrientation(orientation);
+ }
+ mCurrentScreenOrientation = Optional.empty();
+ });
+ }
+}
diff --git a/src/com/android/wallpaper/picker/TouchForwardingLayout2.java b/src/com/android/wallpaper/picker/TouchForwardingLayout2.java
new file mode 100644
index 0000000..d83700e
--- /dev/null
+++ b/src/com/android/wallpaper/picker/TouchForwardingLayout2.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.picker;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+/**
+ * A frame layout that listens to touch events and routes them to another view.
+ * TODO b/256819974 This is a duplicate of TouchForwardingLayout and should be removed after
+ * TouchForwardingLayout in the branch of tm-qpr-dev is synced with master.
+ */
+public class TouchForwardingLayout2 extends FrameLayout {
+
+ private View mView;
+ private boolean mForwardingEnabled;
+
+ public TouchForwardingLayout2(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (mView != null && mForwardingEnabled) {
+ mView.dispatchTouchEvent(ev);
+ }
+ return true;
+ }
+
+ /** Set the view that the touch events are routed to */
+ public void setTargetView(View view) {
+ mView = view;
+ }
+
+ public void setForwardingEnabled(boolean forwardingEnabled) {
+ mForwardingEnabled = forwardingEnabled;
+ }
+}
diff --git a/src/com/android/wallpaper/util/SystemColors.kt b/src/com/android/wallpaper/util/SystemColors.kt
new file mode 100644
index 0000000..ec1738c
--- /dev/null
+++ b/src/com/android/wallpaper/util/SystemColors.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.util
+
+import android.annotation.AttrRes
+import android.annotation.ColorInt
+import android.content.Context
+import android.util.TypedValue
+import androidx.core.content.ContextCompat
+
+object SystemColors {
+
+ /**
+ * Returns the color by fetching the resId from the theme. Throws an exception when resource Id
+ * is not available in the theme.
+ */
+ @JvmStatic
+ @ColorInt
+ fun getColor(context: Context, @AttrRes resId: Int): Int {
+ val colorValue = TypedValue()
+ val theme = context.theme
+ if (theme.resolveAttribute(resId, colorValue, /* resolveRefs= */ true)) {
+ if (
+ TypedValue.TYPE_FIRST_COLOR_INT <= colorValue.type &&
+ colorValue.type <= TypedValue.TYPE_LAST_COLOR_INT
+ ) {
+ return colorValue.data
+ }
+ if (colorValue.type == TypedValue.TYPE_STRING) {
+ return ContextCompat.getColor(context, colorValue.resourceId)
+ }
+ }
+ throw IllegalArgumentException(
+ "Theme is missing expected color ${context.resources.getResourceName(resId)} " +
+ "($resId) references a missing resource."
+ )
+ }
+}
diff --git a/src/com/android/wallpaper/widget/DuoTabs.java b/src/com/android/wallpaper/widget/DuoTabs.java
new file mode 100644
index 0000000..8b78508
--- /dev/null
+++ b/src/com/android/wallpaper/widget/DuoTabs.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.util.SystemColors;
+
+/**
+ * Custom layout for duo tabs.
+ */
+public final class DuoTabs extends FrameLayout {
+
+ public static final int TAB_PRIMARY = 0;
+ public static final int TAB_SECONDARY = 1;
+
+ /**
+ * Overlay tab
+ */
+ @IntDef({TAB_PRIMARY, TAB_SECONDARY})
+ public @interface Tab {
+ }
+
+ /**
+ * Overlay tab selected listener
+ */
+ public interface OnTabSelectedListener {
+
+ /**
+ * On tab selected
+ */
+ void onTabSelected(@Tab int tab);
+ }
+
+ OnTabSelectedListener mOnTabSelectedListener;
+ Button mPrimaryTab;
+ Button mSecondaryTab;
+ @Tab int mCurrentOverlayTab;
+
+ /**
+ * Constructor
+ */
+ public DuoTabs(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater.from(context).inflate(R.layout.duo_tabs, this, true);
+ mPrimaryTab = findViewById(R.id.tab_primary);
+ mSecondaryTab = findViewById(R.id.tab_secondary);
+ mPrimaryTab.setOnClickListener(v -> selectTab(TAB_PRIMARY));
+ mSecondaryTab.setOnClickListener(v -> selectTab(TAB_SECONDARY));
+ }
+
+ /**
+ * Set tab text
+ */
+ public void setTabText(String primaryTabText, String secondaryTabText) {
+ mPrimaryTab.setText(primaryTabText);
+ mSecondaryTab.setText(secondaryTabText);
+ }
+
+ /**
+ * Select a tab
+ */
+ public void selectTab(@Tab int tab) {
+ updateTabIndicator(tab);
+ if (mOnTabSelectedListener != null) {
+ mOnTabSelectedListener.onTabSelected(tab);
+ }
+ mCurrentOverlayTab = tab;
+ }
+
+ /**
+ * Set listener
+ */
+ public void setOnTabSelectedListener(
+ OnTabSelectedListener onTabSelectedListener) {
+ mOnTabSelectedListener = onTabSelectedListener;
+ }
+
+ /**
+ * Update the background color in case the context theme has changed.
+ */
+ public void updateBackgroundColor() {
+ mPrimaryTab.setBackground(null);
+ mSecondaryTab.setBackground(null);
+ updateTabIndicator(mCurrentOverlayTab);
+ }
+
+ private void updateTabIndicator(@Tab int tab) {
+ Context c = getContext();
+ mPrimaryTab.setBackgroundResource(
+ tab == TAB_PRIMARY
+ ? R.drawable.duo_tabs_button_indicator_background
+ : R.drawable.duo_tabs_button_background);
+ mPrimaryTab.setTextColor(
+ tab == TAB_PRIMARY
+ ? SystemColors.getColor(c, com.android.internal.R.attr.textColorOnAccent)
+ : SystemColors.getColor(c, android.R.attr.textColorPrimary));
+ mSecondaryTab.setBackgroundResource(
+ tab == TAB_SECONDARY
+ ? R.drawable.duo_tabs_button_indicator_background
+ : R.drawable.duo_tabs_button_background);
+ mSecondaryTab.setTextColor(
+ tab == TAB_SECONDARY
+ ? SystemColors.getColor(c, com.android.internal.R.attr.textColorOnAccent)
+ : SystemColors.getColor(c, android.R.attr.textColorPrimary));
+ }
+}
diff --git a/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java b/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java
new file mode 100644
index 0000000..462dbb4
--- /dev/null
+++ b/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 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.wallpaper.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.CompoundButton;
+import android.widget.FrameLayout;
+import android.widget.ToggleButton;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
+
+import com.android.wallpaper.R;
+
+/**
+ * Custom layout for tabs to select in between home screen overlay or lock screen overlay.
+ */
+public final class WallpaperControlButtonGroup extends FrameLayout {
+
+ public static final int INFORMATION = 0;
+ public static final int EFFECTS = 1;
+
+ /**
+ * Overlay tab
+ */
+ @IntDef({INFORMATION, EFFECTS})
+ public @interface WallpaperControlType {
+ }
+
+ ToggleButton mInformationButton;
+ ToggleButton mEffectsButton;
+
+ /**
+ * Constructor
+ */
+ public WallpaperControlButtonGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater.from(context).inflate(R.layout.wallpaper_control_button_group, this, true);
+ mInformationButton = findViewById(R.id.information_button);
+ mEffectsButton = findViewById(R.id.effects_button);
+ }
+
+ /**
+ * Show a button by giving a correspondent listener
+ */
+ public void showButton(@WallpaperControlType int type,
+ CompoundButton.OnCheckedChangeListener listener) {
+ switch (type) {
+ case INFORMATION:
+ mInformationButton.setVisibility(VISIBLE);
+ mInformationButton.setOnCheckedChangeListener(listener);
+ break;
+ case EFFECTS:
+ mEffectsButton.setVisibility(VISIBLE);
+ mEffectsButton.setOnCheckedChangeListener(listener);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Set checked for a button
+ */
+ public void setChecked(@WallpaperControlType int type, boolean checked) {
+ switch (type) {
+ case INFORMATION:
+ mInformationButton.setChecked(checked);
+ break;
+ case EFFECTS:
+ mEffectsButton.setChecked(checked);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Update the background color in case the context theme has changed.
+ */
+ public void updateBackgroundColor() {
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+ mInformationButton.setForeground(null);
+ mEffectsButton.setForeground(null);
+ mInformationButton.setForeground(
+ AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_info));
+ mEffectsButton.setForeground(AppCompatResources.getDrawable(context,
+ R.drawable.wallpaper_control_button_effect));
+ }
+}