diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:31:05 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:31:05 +0000 |
commit | 9e687f4853f4afa17d8180bfe154f2fca743367e (patch) | |
tree | 5d5ab5b75e521a32cd3cebe20209d9af46887f5a | |
parent | 20ba591019b8d4364ac74723b08a7b530a169c8a (diff) | |
parent | ef09f446ae2325df039f7c6ada060d93d18c92d5 (diff) |
Snap for 10276566 from ef09f446ae2325df039f7c6ada060d93d18c92d5 to tm-platform-release
Change-Id: I2beedbe274f3a497f4e1d5eb21d1e6f1f11fe655
246 files changed, 7525 insertions, 1120 deletions
@@ -29,6 +29,7 @@ android_library { "androidx.cardview_cardview", "androidx-constraintlayout_constraintlayout", "androidx.exifinterface_exifinterface", + "androidx.lifecycle_lifecycle-livedata-ktx", "androidx.lifecycle_lifecycle-runtime-ktx", "androidx.recyclerview_recyclerview", "androidx.slice_slice-view", diff --git a/res/drawable/bottom_connected_section_background.xml b/res/drawable/bottom_connected_section_background.xml new file mode 100644 index 00000000..6e1faf6e --- /dev/null +++ b/res/drawable/bottom_connected_section_background.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle"> + + <solid android:color="@color/color_surface" /> + + <corners + android:topLeftRadius="8dp" + android:topRightRadius="8dp" + android:bottomLeftRadius="32dp" + android:bottomRightRadius="32dp" /> +</shape> diff --git a/res/drawable/duo_tabs_divider.xml b/res/drawable/duo_tabs_divider.xml index 8325048c..364994f4 100644 --- a/res/drawable/duo_tabs_divider.xml +++ b/res/drawable/duo_tabs_divider.xml @@ -17,5 +17,5 @@ <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 + android:width="@dimen/spacing_8dp" /> +</shape> diff --git a/res/drawable/exit_full_preview_cross.xml b/res/drawable/exit_full_preview_cross.xml new file mode 100644 index 00000000..e3d341fe --- /dev/null +++ b/res/drawable/exit_full_preview_cross.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_on_background" /> + <item android:drawable="@drawable/ic_close" /> +</layer-list>
\ No newline at end of file diff --git a/res/drawable/gradient_black_scrim.xml b/res/drawable/gradient_black_scrim.xml new file mode 100644 index 00000000..494b3714 --- /dev/null +++ b/res/drawable/gradient_black_scrim.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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> + <shape> + <gradient + android:angle="90" + android:startColor="@android:color/transparent" + android:centerColor="@android:color/transparent" + android:endColor="@color/wallpaper_preview_scrim_color" + android:centerY="0.8" /> + </shape> + </item> + + <item> + <shape> + <gradient + android:angle="90" + android:startColor="@color/wallpaper_preview_scrim_color" + android:centerColor="@android:color/transparent" + android:endColor="@android:color/transparent" + android:centerY="0.2" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/res/drawable/horizontal_divider_10dp.xml b/res/drawable/horizontal_divider_10dp.xml new file mode 100644 index 00000000..20a112b4 --- /dev/null +++ b/res/drawable/horizontal_divider_10dp.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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:width="@dimen/spacing_10dp" + android:height="0dp" /> +</shape> diff --git a/res/drawable/horizontal_divider_24dp.xml b/res/drawable/horizontal_divider_24dp.xml new file mode 100644 index 00000000..2f267732 --- /dev/null +++ b/res/drawable/horizontal_divider_24dp.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 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="24dp" /> +</shape>
\ No newline at end of file diff --git a/res/drawable/horizontal_divider_8dp.xml b/res/drawable/horizontal_divider_8dp.xml index b45de7bd..dc60750f 100644 --- a/res/drawable/horizontal_divider_8dp.xml +++ b/res/drawable/horizontal_divider_8dp.xml @@ -16,6 +16,6 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <size - android:width="8dp" + android:width="@dimen/spacing_8dp" android:height="0dp" /> </shape> diff --git a/res/drawable/ic_close.xml b/res/drawable/ic_close.xml new file mode 100644 index 00000000..bd0d8341 --- /dev/null +++ b/res/drawable/ic_close.xml @@ -0,0 +1,11 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tintMode="multiply" + android:tint="@color/text_color_on_accent"> + <path + android:fillColor="@android:color/white" + android:pathData="M249,753L207,711L438,480L207,249L249,207L480,438L711,207L753,249L522,480L753,711L711,753L480,522L249,753Z"/> +</vector> diff --git a/res/drawable/ic_device_reset.xml b/res/drawable/ic_device_reset.xml new file mode 100644 index 00000000..a100492a --- /dev/null +++ b/res/drawable/ic_device_reset.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48" + android:tintMode="multiply" + android:tint="@color/wallpaper_control_button_ic_color_tint"> + <path + android:fillColor="@android:color/white" + android:pathData="M23.85,42Q16.4,42 11.2,36.725Q6,31.45 6,23.95H9Q9,30.2 13.3,34.6Q17.6,39 23.85,39Q30.2,39 34.6,34.55Q39,30.1 39,23.75Q39,17.55 34.55,13.275Q30.1,9 23.85,9Q20.45,9 17.475,10.55Q14.5,12.1 12.3,14.65H17.55V17.65H7.1V7.25H10.1V12.55Q12.7,9.5 16.275,7.75Q19.85,6 23.85,6Q27.6,6 30.9,7.4Q34.2,8.8 36.675,11.225Q39.15,13.65 40.575,16.9Q42,20.15 42,23.9Q42,27.65 40.575,30.95Q39.15,34.25 36.675,36.7Q34.2,39.15 30.9,40.575Q27.6,42 23.85,42ZM30.25,32.15 L22.55,24.55V13.85H25.55V23.3L32.4,30Z"/> +</vector> diff --git a/res/drawable/ic_edit.xml b/res/drawable/ic_edit.xml new file mode 100644 index 00000000..ed268ead --- /dev/null +++ b/res/drawable/ic_edit.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2023 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="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48" + android:tintMode="multiply" + android:tint="@color/wallpaper_control_button_ic_color_tint"> + <path + android:fillColor="@android:color/white" + android:pathData="M9,39H11.2L35.45,14.75L34.35,13.65L33.25,12.55L9,36.8ZM6,42V35.6L35.4,6.2Q36.25,5.35 37.525,5.375Q38.8,5.4 39.65,6.25L41.8,8.4Q42.65,9.25 42.65,10.5Q42.65,11.75 41.8,12.6L12.4,42ZM39.5,10.45 L37.45,8.4ZM35.45,14.75 L34.35,13.65 33.25,12.55 35.45,14.75Z"/> +</vector>
\ No newline at end of file diff --git a/res/drawable/ic_share.xml b/res/drawable/ic_share.xml new file mode 100644 index 00000000..5b8b29d8 --- /dev/null +++ b/res/drawable/ic_share.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2023 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="M18,16c-0.79,0 -1.5,0.31 -2.03,0.81L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.53,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.48 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.05,4.12c-0.05,0.22 -0.09,0.45 -0.09,0.69 0,1.66 1.34,3 3,3s3,-1.34 3,-3 -1.34,-3 -3,-3zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z"/> +</vector> diff --git a/res/drawable/leftmost_connected_section_background.xml b/res/drawable/leftmost_connected_section_background.xml new file mode 100644 index 00000000..e32dfd39 --- /dev/null +++ b/res/drawable/leftmost_connected_section_background.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle"> + + <solid android:color="@color/color_surface" /> + + <corners + android:topLeftRadius="32dp" + android:topRightRadius="8dp" + android:bottomLeftRadius="32dp" + android:bottomRightRadius="8dp" /> +</shape> diff --git a/res/drawable/option_item_background.xml b/res/drawable/option_item_background.xml new file mode 100644 index 00000000..0e8d1f13 --- /dev/null +++ b/res/drawable/option_item_background.xml @@ -0,0 +1,21 @@ +<!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle"> + <corners android:radius="20dp" /> + <solid android:color="@color/color_surface_variant" /> +</shape> diff --git a/res/drawable/option_item_border.xml b/res/drawable/option_item_border.xml new file mode 100644 index 00000000..22420b10 --- /dev/null +++ b/res/drawable/option_item_border.xml @@ -0,0 +1,25 @@ + +<!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle" > + <stroke + android:width="2dp" + android:color="@color/text_color_primary" /> + <corners android:radius="20dp" /> +</shape> diff --git a/res/drawable/primary_dialog_button_background.xml b/res/drawable/primary_dialog_button_background.xml new file mode 100644 index 00000000..a641f704 --- /dev/null +++ b/res/drawable/primary_dialog_button_background.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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"> + <solid android:color="@android:color/white" /> + <corners android:radius="50dp" /> + </shape> + </item> + + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <solid android:color="@color/color_accent_primary" /> + <corners android:radius="50dp" /> + </shape> + </item> +</ripple> diff --git a/res/drawable/rightmost_connected_section_background.xml b/res/drawable/rightmost_connected_section_background.xml new file mode 100644 index 00000000..72cdc9dd --- /dev/null +++ b/res/drawable/rightmost_connected_section_background.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle"> + + <solid android:color="@color/color_surface" /> + + <corners + android:topLeftRadius="8dp" + android:topRightRadius="32dp" + android:bottomLeftRadius="8dp" + android:bottomRightRadius="32dp" /> +</shape> diff --git a/res/drawable/secondary_dialog_button_background.xml b/res/drawable/secondary_dialog_button_background.xml new file mode 100644 index 00000000..7b0ad340 --- /dev/null +++ b/res/drawable/secondary_dialog_button_background.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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"> + <solid android:color="@android:color/white" /> + <corners android:radius="50dp" /> + </shape> + </item> + + <item android:id="@android:id/background"> + <shape android:shape="rectangle"> + <stroke android:color="@color/color_accent_primary" android:width="1dp" /> + <corners android:radius="50dp" /> + </shape> + </item> +</ripple> diff --git a/res/drawable/vertical_divider_24dp.xml b/res/drawable/vertical_divider_24dp.xml new file mode 100644 index 00000000..22b61ad6 --- /dev/null +++ b/res/drawable/vertical_divider_24dp.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 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="24dp" + android:width="0dp" /> +</shape>
\ No newline at end of file diff --git a/res/drawable/wallpaper_control_button_edit.xml b/res/drawable/wallpaper_control_button_edit.xml new file mode 100644 index 00000000..ee9bc43a --- /dev/null +++ b/res/drawable/wallpaper_control_button_edit.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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_edit" /> +</layer-list>
\ No newline at end of file diff --git a/res/drawable/wallpaper_control_button_share.xml b/res/drawable/wallpaper_control_button_share.xml new file mode 100644 index 00000000..39c29dd1 --- /dev/null +++ b/res/drawable/wallpaper_control_button_share.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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_share" /> +</layer-list>
\ No newline at end of file diff --git a/res/drawable/wallpaper_quick_switch_option_background.xml b/res/drawable/wallpaper_quick_switch_option_background.xml new file mode 100644 index 00000000..a2e029f4 --- /dev/null +++ b/res/drawable/wallpaper_quick_switch_option_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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" + android:shape="rectangle"> + <corners android:radius="12dp" /> +</shape> diff --git a/res/drawable/wallpaper_quick_switch_option_selection_marker_background.xml b/res/drawable/wallpaper_quick_switch_option_selection_marker_background.xml new file mode 100644 index 00000000..b4bbdebb --- /dev/null +++ b/res/drawable/wallpaper_quick_switch_option_selection_marker_background.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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"> + + <!-- Inner border --> + <item> + <shape android:shape="rectangle"> + <stroke + android:color="@color/color_surface" + android:width="8dp" /> + <corners android:radius="12dp" /> + </shape> + </item> + + <!-- Outer border --> + <item> + <shape android:shape="rectangle"> + <stroke + android:color="@color/text_color_primary" + android:width="2dp" /> + <corners android:radius="12dp" /> + </shape> + </item> +</layer-list> diff --git a/res/layout-w600dp/responsive_section.xml b/res/layout-w600dp/responsive_section.xml new file mode 100644 index 00000000..d6086859 --- /dev/null +++ b/res/layout-w600dp/responsive_section.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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. + ~ + --> + +<com.android.wallpaper.picker.customization.ui.section.ResponsiveLayoutSectionView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/tab_container_horizontal_padding" + android:orientation="horizontal" + android:divider="@drawable/horizontal_divider_24dp" + android:showDividers="middle" + /> diff --git a/res/layout/dialog_button.xml b/res/layout/dialog_button.xml new file mode 100644 index 00000000..574bfea7 --- /dev/null +++ b/res/layout/dialog_button.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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. + ~ + --> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> diff --git a/res/layout/dialog_view.xml b/res/layout/dialog_view.xml new file mode 100644 index 00000000..fd21f1e6 --- /dev/null +++ b/res/layout/dialog_view.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center_horizontal" + android:padding="24dp"> + + <ImageView + android:id="@+id/icon" + android:layout_width="32dp" + android:layout_height="32dp" + android:tint="@color/color_accent_primary" + tools:ignore="UseAppTint" /> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline" + android:textColor="@color/text_color_primary" + android:maxLines="2" + android:ellipsize="end" /> + + <TextView + android:id="@+id/message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" + android:textColor="@color/text_color_secondary" /> + + <LinearLayout + android:id="@+id/button_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical|end" + android:layout_marginTop="32dp" + android:divider="@drawable/horizontal_divider_10dp" + android:showDividers="middle" /> + +</LinearLayout> diff --git a/res/layout/duo_tabs.xml b/res/layout/duo_tabs.xml index 5a253761..9393cb0e 100644 --- a/res/layout/duo_tabs.xml +++ b/res/layout/duo_tabs.xml @@ -22,7 +22,7 @@ android:orientation="horizontal" android:showDividers="middle"> - <Button + <TextView android:id="@+id/tab_primary" android:layout_width="match_parent" android:layout_height="@dimen/separated_tabs_height" @@ -30,7 +30,7 @@ android:background="@drawable/duo_tabs_button_background" android:gravity="center" /> - <Button + <TextView android:id="@+id/tab_secondary" android:layout_width="match_parent" android:layout_height="@dimen/separated_tabs_height" diff --git a/res/layout/fragment_clock_custom_picker_demo.xml b/res/layout/fragment_clock_custom_picker_demo.xml deleted file mode 100644 index 29bd9413..00000000 --- a/res/layout/fragment_clock_custom_picker_demo.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <FrameLayout - android:id="@+id/section_header_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:layout_constraintBottom_toTopOf="@+id/clock_preview_card_list_demo" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent"> - <include layout="@layout/section_header" /> - </FrameLayout> - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/clock_preview_card_list_demo" - android:layout_width="match_parent" - android:layout_height="0dp" - app:layout_constraintBottom_toBottomOf="parent" - android:paddingHorizontal="@dimen/grid_options_container_horizontal_margin" - app:layout_constraintTop_toBottomOf="@+id/section_header_container" - android:clipToPadding="false" /> -</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/res/layout/fragment_customization_picker.xml b/res/layout/fragment_customization_picker.xml index c95c61cb..6bef55cd 100755 --- a/res/layout/fragment_customization_picker.xml +++ b/res/layout/fragment_customization_picker.xml @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<com.android.customization.picker.HorizontalTouchMovementAwareNestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scroll_container" android:layout_width="match_parent" android:layout_height="match_parent" @@ -27,4 +27,4 @@ android:layout_height="match_parent" android:layout_marginVertical="@dimen/section_container_vertical_margin" android:orientation="vertical" /> -</androidx.core.widget.NestedScrollView> +</com.android.customization.picker.HorizontalTouchMovementAwareNestedScrollView> diff --git a/res/layout/fragment_tabbed_customization_picker.xml b/res/layout/fragment_tabbed_customization_picker.xml index e0566703..0a3eda8c 100644 --- a/res/layout/fragment_tabbed_customization_picker.xml +++ b/res/layout/fragment_tabbed_customization_picker.xml @@ -25,7 +25,7 @@ android:id="@+id/duo_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingHorizontal="24dp" + android:paddingHorizontal="@dimen/tab_container_horizontal_padding" android:paddingVertical="16dp" /> <include diff --git a/res/layout/fragment_wallpaper_preview.xml b/res/layout/fragment_wallpaper_preview.xml index bc73fa83..70d35385 100644 --- a/res/layout/fragment_wallpaper_preview.xml +++ b/res/layout/fragment_wallpaper_preview.xml @@ -34,6 +34,13 @@ <include layout="@layout/wallpaper_preview" /> + <View + android:id="@+id/preview_scrim" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/gradient_black_scrim" + android:importantForAccessibility="noHideDescendants" /> + <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" @@ -54,6 +61,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@drawable/set_wallpaper_button_background" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" android:gravity="center" android:text="@string/set_wallpaper_button_text" android:textColor="@color/text_color_on_accent" @@ -62,11 +70,27 @@ app:layout_constraintTop_toTopOf="@+id/toolbar" app:layout_constraintBottom_toBottomOf="@+id/toolbar" /> + <View + android:id="@+id/exit_full_preview_button" + android:layout_width="@dimen/wallpaper_control_button_size" + android:layout_height="@dimen/wallpaper_control_button_size" + android:layout_gravity="center_vertical" + android:foreground="@drawable/exit_full_preview_cross" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" + android:gravity="center" + android:layout_marginEnd="@dimen/set_wallpaper_button_margin_end" + android:visibility="gone" + android:clickable="true" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="@+id/toolbar" + app:layout_constraintBottom_toBottomOf="@+id/toolbar" /> + <com.android.wallpaper.widget.WallpaperDownloadButton android:id="@+id/button_download_wallpaper" android:layout_width="@dimen/wallpaper_control_button_size" android:layout_height="@dimen/wallpaper_control_button_size" android:layout_marginEnd="@dimen/wallpaper_control_button_group_margin_end" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/toolbar" app:layout_constraintBottom_toBottomOf="@+id/toolbar" @@ -102,6 +126,17 @@ android:paddingHorizontal="@dimen/full_preview_page_tabs_horizontal_padding" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" /> + + <ProgressBar + android:id="@+id/action_progress" + android:layout_width="@dimen/effect_generating_progress_bar_size" + android:layout_height="@dimen/effect_generating_progress_bar_size" + android:indeterminateTint="?android:attr/textColorSecondary" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> <com.android.wallpaper.widget.FloatingSheet diff --git a/res/layout/responsive_section.xml b/res/layout/responsive_section.xml new file mode 100644 index 00000000..444967f0 --- /dev/null +++ b/res/layout/responsive_section.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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. + ~ + --> + +<com.android.wallpaper.picker.customization.ui.section.ResponsiveLayoutSectionView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingHorizontal="@dimen/tab_container_horizontal_padding" + android:orientation="vertical" + android:divider="@drawable/vertical_divider_24dp" + android:showDividers="middle" /> diff --git a/res/layout/screen_preview_section.xml b/res/layout/screen_preview_section.xml index fde66113..527c0dc6 100644 --- a/res/layout/screen_preview_section.xml +++ b/res/layout/screen_preview_section.xml @@ -20,24 +20,41 @@ android:layout_height="wrap_content" android:paddingBottom="16dp"> - <com.android.wallpaper.picker.DisplayAspectRatioFrameLayout + <FrameLayout android:layout_width="match_parent" - android:layout_height="@dimen/screen_preview_height"> + android:layout_height="wrap_content"> - <include - android:id="@+id/lock_preview" - layout="@layout/wallpaper_preview_card" + <com.android.wallpaper.picker.DisplayAspectRatioFrameLayout + android:layout_width="match_parent" + android:layout_height="@dimen/screen_preview_height"> + + <include + android:id="@+id/lock_preview" + layout="@layout/wallpaper_preview_card" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" /> + + <include + android:id="@+id/home_preview" + layout="@layout/wallpaper_preview_card" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" /> + + </com.android.wallpaper.picker.DisplayAspectRatioFrameLayout> + + <ViewStub + android:id="@+id/clock_carousel_view_stub" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" /> - <include - android:id="@+id/home_preview" - layout="@layout/wallpaper_preview_card" + <ViewStub + android:id="@+id/single_clock_view_stub" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" /> - - </com.android.wallpaper.picker.DisplayAspectRatioFrameLayout> + </FrameLayout> </com.android.wallpaper.picker.customization.ui.section.ScreenPreviewView> diff --git a/res/layout/toolbar_container_layout.xml b/res/layout/toolbar_container_layout.xml new file mode 100644 index 00000000..c1fc9a11 --- /dev/null +++ b/res/layout/toolbar_container_layout.xml @@ -0,0 +1,31 @@ +<?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/content_parent" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <include layout="@layout/section_header" /> + + <FrameLayout + android:id="@+id/content_frame" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/wallpaper_control_button_group.xml b/res/layout/wallpaper_control_button_group.xml index ecc73fcb..966aa189 100644 --- a/res/layout/wallpaper_control_button_group.xml +++ b/res/layout/wallpaper_control_button_group.xml @@ -27,17 +27,31 @@ android:layout_height="@dimen/wallpaper_control_button_size" android:background="@android:color/transparent" android:contentDescription="@string/delete_live_wallpaper" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" android:foreground="@drawable/wallpaper_control_button_delete" android:textOff="" android:textOn="" android:visibility="gone" /> <ToggleButton + android:id="@+id/edit_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/edit_live_wallpaper" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" + android:foreground="@drawable/wallpaper_control_button_edit" + android:textOff="" + android:textOn="" + android:visibility="gone" /> + + <ToggleButton android:id="@+id/customize_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_customize" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" android:foreground="@drawable/wallpaper_control_button_customize" android:textOff="" android:textOn="" @@ -49,17 +63,30 @@ android:layout_height="@dimen/wallpaper_control_button_size" android:background="@android:color/transparent" android:contentDescription="@string/tab_effects" + android:elevation="@dimen/wallpaper_preview_buttons_elevation" android:foreground="@drawable/wallpaper_control_button_effect" android:textOff="" android:textOn="" android:visibility="gone" /> <ToggleButton + android:id="@+id/share_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_share" + android:foreground="@drawable/wallpaper_control_button_share" + 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:elevation="@dimen/wallpaper_preview_buttons_elevation" android:foreground="@drawable/wallpaper_control_button_info" android:textOff="" android:textOn="" diff --git a/res/layout/wallpaper_preview_card.xml b/res/layout/wallpaper_preview_card.xml index 69de5833..266bb386 100644 --- a/res/layout/wallpaper_preview_card.xml +++ b/res/layout/wallpaper_preview_card.xml @@ -31,6 +31,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + <!-- A 30% opacity black scrim that can be shown to "dim" the wallpaper. --> + <View + android:id="@+id/wallpaper_dimming_scrim" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/wallpaper_preview_scrim_color" + android:visibility="invisible" + android:importantForAccessibility="noHideDescendants" /> + <SurfaceView android:id="@+id/workspace_surface" android:layout_width="match_parent" @@ -51,4 +60,14 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> + + <ImageView + android:id="@+id/wallpaper_fadein_scrim" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/color_surface" + android:forceHasOverlappingRendering="false" + android:importantForAccessibility="no" + android:visibility="invisible" /> + </androidx.cardview.widget.CardView> diff --git a/res/layout/wallpaper_quick_switch_option.xml b/res/layout/wallpaper_quick_switch_option.xml new file mode 100644 index 00000000..ad61cb34 --- /dev/null +++ b/res/layout/wallpaper_quick_switch_option.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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="wrap_content" + android:layout_height="@dimen/wallpaper_quick_switch_selected_option_height" + android:background="@drawable/wallpaper_quick_switch_option_background" + android:clipToOutline="true"> + + <ImageView + android:id="@+id/placeholder" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <ImageView + android:id="@+id/thumbnail" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="centerCrop" + android:visibility="gone" /> + + <ImageView + android:id="@+id/selection_border" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/wallpaper_quick_switch_option_selection_marker_background" + android:visibility="gone" /> + + <ImageView + android:id="@+id/selection_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:src="@drawable/check_circle_accent_24dp" + android:visibility="gone" /> + + <ProgressBar + android:id="@+id/progress_indicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone" /> + +</FrameLayout>
\ No newline at end of file diff --git a/res/layout/wallpaper_quick_switch_section.xml b/res/layout/wallpaper_quick_switch_section.xml new file mode 100644 index 00000000..a7df6f8f --- /dev/null +++ b/res/layout/wallpaper_quick_switch_section.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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. +--> +<com.android.wallpaper.picker.customization.ui.section.WallpaperQuickSwitchView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="24dp" + android:orientation="vertical" + android:background="@drawable/bottom_connected_section_background" + android:paddingTop="16dp" + android:paddingBottom="10dp" + android:paddingHorizontal="24dp"> + <!-- + See ResponsiveLayoutSectionController to see whether and how the background is replaced in code. + --> + + <LinearLayout + android:id="@+id/options" + android:layout_width="match_parent" + android:layout_height="@dimen/wallpaper_quick_switch_selected_option_height" + android:orientation="horizontal" + android:divider="@drawable/horizontal_divider_8dp" + android:showDividers="middle" /> + + <TextView + android:id="@+id/more_wallpapers" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="10dp" + android:minHeight="48dp" + android:gravity="center" + android:drawablePadding="12dp" + android:drawableStart="@drawable/ic_nav_wallpaper" + android:drawableTint="@color/text_color_primary" + android:text="@string/more_wallpapers" + android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" + android:textColor="@color/text_color_primary" + tools:ignore="UseCompatTextViewDrawableXml" /> + +</com.android.wallpaper.picker.customization.ui.section.WallpaperQuickSwitchView> diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 3d2919f8..0d974f30 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Inligting"</string> <string name="tab_customize" msgid="2533745409174959960">"Pasmaak"</string> <string name="tab_effects" msgid="3213606157589233901">"Effekte"</string> + <string name="tab_share" msgid="6676269624804601227">"Deel"</string> <string name="my_photos" msgid="8613021349284084982">"My foto\'s"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Instellings …"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Vee uit"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vee hierdie muurpapier op jou foon uit?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Wysig"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vee hierdie muurpapier op jou toestel uit?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Terug"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Wysig"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Laai af"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Sluitskerm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Tuisskerm"</string> <string name="reset" msgid="4945445169532850631">"Stel terug"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Is jy seker?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Dit sal alle veranderinge wat jy gemaak het, terugstel."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Stel veranderinge terug?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Jou veranderinge sal nie gestoor word nie"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Nog muurpapiere"</string> </resources> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index 60a485a8..28fd1a89 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"መረጃ"</string> <string name="tab_customize" msgid="2533745409174959960">"ብጁ አድርግ"</string> <string name="tab_effects" msgid="3213606157589233901">"ተጽዕኖዎች"</string> + <string name="tab_share" msgid="6676269624804601227">"አጋራ"</string> <string name="my_photos" msgid="8613021349284084982">"የእኔ ፎቶዎች"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ቅንብሮች…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ሰርዝ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ይህ ልጣፍ ከስልክዎ ይሰረዝ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"አርትዕ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ይህ ልጣፍ ከመሣሪያዎ ይሰረዝ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ተመለስ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"አርትዕ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"አውርድ"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ማያ ገፅ ቁልፍ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"መነሻ ማያ ገፅ"</string> <string name="reset" msgid="4945445169532850631">"ዳግም አስጀምር"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"እርግጠኛ ነዎት?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ይህ ሁሉንም ያደረጓቸውን ለውጦች ዳግም ያስጀምራቸዋል።"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ለውጦች ዳግም ይጀመሩ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"የእርስዎ ለውጦች አይቀመጡም"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ተጨማሪ ልጣፎች"</string> </resources> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index d2b6e1b7..b1709092 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -21,7 +21,7 @@ <!-- no translation found for app_name (8773648973927541493) --> <skip /> <string name="select_wallpaper_label" msgid="6989581259339646085">"فئات الخلفيات"</string> - <string name="set_wallpaper_button_text" msgid="4426286890442731310">"ضبط كصورة خلفية"</string> + <string name="set_wallpaper_button_text" msgid="4426286890442731310">"الضبط كخلفية"</string> <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"جارٍ تعيين الخلفية…"</string> <string name="try_again" msgid="8278874823700921234">"إعادة المحاولة"</string> <string name="set_wallpaper_error_message" msgid="6819986999041085130">"يتعذّر تعيين الخلفية."</string> @@ -54,7 +54,7 @@ <string name="next_wallpaper" msgid="3911873152952596232">"الخلفية التالية"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"تم إيقاف إمكانية تعيين خلفية على هذا الجهاز."</string> <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"أوقف مشرف الجهاز إمكانية تعيين خلفية."</string> - <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"تم ضبط الخلفية بنجاح."</string> + <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"تم تطبيق الخلفية بنجاح"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"يلزمك الاتصال بالإنترنت للاطّلاع على الخلفيات. يُرجى الاتصال وإعادة المحاولة."</string> <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"صورة مصغَّرة لخلفية الشاشة الرئيسية المعيَّنة حاليًا"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"صورة مصغَّرة لخلفية شاشة القفل المعيَّنة حاليًا"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"معلومات"</string> <string name="tab_customize" msgid="2533745409174959960">"تخصيص"</string> <string name="tab_effects" msgid="3213606157589233901">"التأثيرات"</string> + <string name="tab_share" msgid="6676269624804601227">"مشاركة"</string> <string name="my_photos" msgid="8613021349284084982">"صوري"</string> <string name="configure_wallpaper" msgid="849882179182976621">"الإعدادات…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"حذف"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"هل تريد حذف هذه الخلفية من هاتفك؟"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"تعديل"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"هل تريد حذف هذه الخلفية من جهازك؟"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"رجوع"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"تعديل"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"تنزيل"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"شاشة القفل"</string> <string name="home_screen_tab" msgid="1080445697837877526">"الشاشة الرئيسية"</string> <string name="reset" msgid="4945445169532850631">"إعادة الضبط"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"هل أنت متأكد؟"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"سيؤدي هذا الإجراء إلى إعادة ضبط كل التغييرات التي أجريتها."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"هل تريد إعادة ضبط التغييرات؟"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"لن يتم حفظ تغييراتك."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"المزيد من الخلفيات"</string> </resources> diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index 136eaabd..3f78195c 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -62,10 +62,10 @@ <string name="wallpaper_thumbnail" msgid="569931475923605974">"ৱালপেপাৰৰ থাম্বনেইল"</string> <string name="explore_home_screen" msgid="8756346794535765482">"গৃহ স্ক্ৰীনৰ ৱালপেপাৰ অন্বেষণ কৰক"</string> <string name="explore_lock_screen" msgid="268938342103703665">"লক স্ক্ৰীনৰ ৱালপেপাৰ অন্বেষণ কৰক"</string> - <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"গৃহ স্ক্ৰীনৰ দৈনিক ৱালপেপাৰ ৰিফ্ৰে’শ্ব কৰক"</string> - <string name="refresh_daily_wallpaper_content_description" msgid="4362142658237147583">"দৈনিক ৱালপেপাৰ ৰিফ্ৰে\'শ্ব কৰক"</string> - <string name="refreshing_daily_wallpaper_dialog_message" msgid="1975910873362855761">"দৈনিক ৱালপেপাৰ ৰিফ্ৰে\'শ্ব কৰি থকা হৈছে …"</string> - <string name="refresh_daily_wallpaper_failed_message" msgid="4749879993812557166">"দৈনিক ৱালপেপাৰ ৰিফ্ৰে\'শ্ব কৰিব পৰা নগ\'ল। অনুগ্ৰহ কৰি আপোনাৰ নেটৱর্ক সংযোগ পৰীক্ষা কৰক আৰু আকৌ চেষ্টা কৰক।"</string> + <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"গৃহ স্ক্ৰীনৰ দৈনিক ৱালপেপাৰ ৰিফ্ৰেশ্ব কৰক"</string> + <string name="refresh_daily_wallpaper_content_description" msgid="4362142658237147583">"দৈনিক ৱালপেপাৰ ৰিফ্ৰেশ্ব কৰক"</string> + <string name="refreshing_daily_wallpaper_dialog_message" msgid="1975910873362855761">"দৈনিক ৱালপেপাৰ ৰিফ্ৰেশ্ব কৰি থকা হৈছে …"</string> + <string name="refresh_daily_wallpaper_failed_message" msgid="4749879993812557166">"দৈনিক ৱালপেপাৰ ৰিফ্ৰেশ্ব কৰিব পৰা নগ\'ল। অনুগ্ৰহ কৰি আপোনাৰ নেটৱর্ক সংযোগ পৰীক্ষা কৰক আৰু আকৌ চেষ্টা কৰক।"</string> <string name="on_device_wallpapers_category_title" msgid="805819102071369004">"ডিভাইচত থকা ৱালপেপাৰ"</string> <string name="on_device_wallpapers_category_title_desktop" msgid="316919420410065369">"ডিভাইচত থকা"</string> <string name="on_device_wallpaper_title" msgid="5262564748034629524">"Android ৱালপেপাৰ"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"তথ্য"</string> <string name="tab_customize" msgid="2533745409174959960">"কাষ্টমাইজ কৰক"</string> <string name="tab_effects" msgid="3213606157589233901">"ইফেক্ট"</string> + <string name="tab_share" msgid="6676269624804601227">"শ্বেয়াৰ কৰক"</string> <string name="my_photos" msgid="8613021349284084982">"মোৰ ফট’"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ছেটিংসমূহ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"মচক"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"এই ৱালপেপাৰখন আপোনাৰ ফ’নটোৰ পৰা মচিবনে?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"সম্পাদনা কৰক"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"আপোনাৰ ডিভাইচটোৰ পৰা এই ৱালপেপাৰখন মচিবনে?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"উভতি যাওক"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"সম্পাদনা কৰক"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ডাউনল’ড কৰক"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"লক স্ক্ৰীন"</string> <string name="home_screen_tab" msgid="1080445697837877526">"গৃহ স্ক্ৰীন"</string> <string name="reset" msgid="4945445169532850631">"ৰিছেট কৰক"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"আপুনি নিশ্চিতনে?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"এইটোৱে আপুনি কৰা আটাইবোৰ সালসলনি ৰিছেট কৰিব।"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"সালসলনিসমূহ ৰিছেট কৰিবনে?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"আপোনাৰ সম্পাদনাবোৰ ছেভ কৰা নহ’ব"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"অধিক ৱালপেপাৰ"</string> </resources> diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 3ab7f418..a7e27b9c 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Məlumat"</string> <string name="tab_customize" msgid="2533745409174959960">"Fərdiləşdirin"</string> <string name="tab_effects" msgid="3213606157589233901">"Effektlər"</string> + <string name="tab_share" msgid="6676269624804601227">"Paylaşın"</string> <string name="my_photos" msgid="8613021349284084982">"Fotolarım"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ayarlar…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Silin"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Bu divar kağızı telefondan silinsin?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Redaktə edin"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Bu divar kağızı cihazınızdan silinsin?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Geri"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Düzəliş"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Endirin"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ekran kilidi"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Əsas ekran"</string> <string name="reset" msgid="4945445169532850631">"Sıfırlayın"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Əminsiniz?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Bu, etdiyiniz bütün dəyişiklikləri sıfırlayacaq."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Dəyişikliklər sıfırlansın?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Dəyişiklikləriniz yadda saxlanılmayacaq"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Digər divar kağızları"</string> </resources> diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index a005273c..667590d1 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacije"</string> <string name="tab_customize" msgid="2533745409174959960">"Prilagodite"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekti"</string> + <string name="tab_share" msgid="6676269624804601227">"Delite"</string> <string name="my_photos" msgid="8613021349284084982">"Moje slike"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Podešavanja…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Izbriši"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Želite da izbrišete ovu pozadinu sa telefona?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Izmeni"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Želite da izbrišete ovu pozadinu sa uređaja?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Nazad"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Izmeni"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Preuzmi"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Zaključani ekran"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Početni ekran"</string> <string name="reset" msgid="4945445169532850631">"Resetuj"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Jeste li sigurni?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ovim resetujete sve promene koje ste uneli."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Želite da resetujete promene?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Promene neće biti sačuvane"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Još pozadina"</string> </resources> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 77756990..965e8777 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Інфармацыя"</string> <string name="tab_customize" msgid="2533745409174959960">"Наладка"</string> <string name="tab_effects" msgid="3213606157589233901">"Эфекты"</string> + <string name="tab_share" msgid="6676269624804601227">"Абагуліць"</string> <string name="my_photos" msgid="8613021349284084982">"Мае фатаграфіі"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Налады…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Выдаліць"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Выдаліць гэтыя шпалеры з тэлефона?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Змяніць"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Выдаліць шпалеры з вашай прылады?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Змяніць"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Спампаваць"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Экран блакіроўкі"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Галоўны экран"</string> <string name="reset" msgid="4945445169532850631">"Скінуць"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Вы ўпэўненыя?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Будуць скінуты ўсе ўнесеныя вамі змяненні."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Скінуць змяненні?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Вашы змяненні не будуць захаваны"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Дадатковыя шпалеры"</string> </resources> diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 773bd1f9..d3556f35 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Информация"</string> <string name="tab_customize" msgid="2533745409174959960">"Персонализиране"</string> <string name="tab_effects" msgid="3213606157589233901">"Ефекти"</string> + <string name="tab_share" msgid="6676269624804601227">"Споделяне"</string> <string name="my_photos" msgid="8613021349284084982">"Моите снимки"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Настройки…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Изтриване"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Да се изтрие ли този тапет от телефона ви?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Редактиране"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Този тапет да се изтрие ли от устройството ви?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Редактиране"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Изтегляне"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Заключен екран"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Начален екран"</string> <string name="reset" msgid="4945445169532850631">"Нулиране"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Наистина ли искате това?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Това действие ще нулира всички направени от вас промени."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Да се нулират ли промените?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Промените ви няма да бъдат запазени"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Още тапети"</string> </resources> diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index c954c727..5a1363c2 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"তথ্য"</string> <string name="tab_customize" msgid="2533745409174959960">"কাস্টমাইজ করুন"</string> <string name="tab_effects" msgid="3213606157589233901">"এফেক্ট"</string> + <string name="tab_share" msgid="6676269624804601227">"শেয়ার করুন"</string> <string name="my_photos" msgid="8613021349284084982">"আমার ফটো"</string> <string name="configure_wallpaper" msgid="849882179182976621">"সেটিংস…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"মুছে দিন"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"আপনার ফোন থেকে এই ওয়ালপেপার মুছে ফেলতে চান?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"এডিট করুন"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"আপনার ডিভাইস থেকে এই ওয়ালপেপার মুছে দেবেন?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ফিরে যান"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"এডিট করুন"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ডাউনলোড করুন"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"লক স্ক্রিন"</string> <string name="home_screen_tab" msgid="1080445697837877526">"হোম স্ক্রিন"</string> <string name="reset" msgid="4945445169532850631">"রিসেট করুন"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"আপনি কি নিশ্চিত?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"এর ফলে আপনার করা সব পরিবর্তন রিসেট হয়ে যাবে।"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"পরিবর্তন রিসেট করবেন?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"আপনার করা পরিবর্তন সেভ করা হবে না"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"আরও ওয়ালপেপার"</string> </resources> diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml index 3432f9af..d30cd8d8 100644 --- a/res/values-bs/strings.xml +++ b/res/values-bs/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacije"</string> <string name="tab_customize" msgid="2533745409174959960">"Prilagođavanje"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekti"</string> + <string name="tab_share" msgid="6676269624804601227">"Dijeli"</string> <string name="my_photos" msgid="8613021349284084982">"Moje fotografije"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Postavke…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Izbriši"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Izbrisati ovu pozadinsku sliku s telefona?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Uredite"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Izbrisati ovu pozadinsku sliku s uređaja?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Nazad"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Uredi"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Preuzmi"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Zaključavanje ekrana"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Početni ekran"</string> <string name="reset" msgid="4945445169532850631">"Poništi"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Jeste li sigurni?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ovim će se poništiti sve promjene koje ste izvršili."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Poništiti izmjene?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Vaše izmjene se neće sačuvati"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Više pozadinskih slika"</string> </resources> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 802e09bd..2fc9d221 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informació"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalitza"</string> <string name="tab_effects" msgid="3213606157589233901">"Efectes"</string> + <string name="tab_share" msgid="6676269624804601227">"Comparteix"</string> <string name="my_photos" msgid="8613021349284084982">"Les meves fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Configuració…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Suprimeix"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vols suprimir aquest fons de pantalla del telèfon?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edita"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vols suprimir aquest fons de pantalla del dispositiu?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Enrere"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edita"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Baixa"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Pantalla de bloqueig"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Pantalla d\'inici"</string> <string name="reset" msgid="4945445169532850631">"Restableix"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Vols continuar?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Es restabliran tots els canvis que hagis fet."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vols restablir els canvis?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Els teus canvis no es desaran"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Més fons de pantalla"</string> </resources> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 5635b896..e3385a21 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informace"</string> <string name="tab_customize" msgid="2533745409174959960">"Přizpůsobení"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekty"</string> + <string name="tab_share" msgid="6676269624804601227">"Sdílení"</string> <string name="my_photos" msgid="8613021349284084982">"Moje fotky"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Nastavení…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Smazat"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Smazat tapetu z telefonu?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Upravit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Smazat tuto tapetu ze zařízení?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Zpět"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Upravit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Stáhnout"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Obrazovka uzamčení"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Plocha"</string> <string name="reset" msgid="4945445169532850631">"Resetovat"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Jste si jisti?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Tímto resetujete všechny provedené změny."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Resetovat změny?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Změny nebudou uloženy"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Další tapety"</string> </resources> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index a98c22ae..49623237 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Oplysninger"</string> <string name="tab_customize" msgid="2533745409174959960">"Tilpas"</string> <string name="tab_effects" msgid="3213606157589233901">"Effekter"</string> + <string name="tab_share" msgid="6676269624804601227">"Del"</string> <string name="my_photos" msgid="8613021349284084982">"Mine billeder"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Indstillinger…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Slet"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vil du slette denne baggrund på din telefon?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Rediger"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vil du slette denne baggrund fra din enhed?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Tilbage"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Rediger"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Låseskærm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Startskærm"</string> <string name="reset" msgid="4945445169532850631">"Nulstil"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Er du sikker?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Dette vil nulstille alle dine ændringer."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vil du nulstille ændringerne?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Dine ændringer gemmes ikke"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Flere baggrunde"</string> </resources> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 26059cea..406f1d66 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informationen"</string> <string name="tab_customize" msgid="2533745409174959960">"Anpassen"</string> <string name="tab_effects" msgid="3213606157589233901">"Effekte"</string> + <string name="tab_share" msgid="6676269624804601227">"Teilen"</string> <string name="my_photos" msgid="8613021349284084982">"Meine Fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Einstellungen…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Löschen"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Diesen Hintergrund von deinem Smartphone löschen?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Bearbeiten"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Diesen Hintergrund von deinem Gerät löschen?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Zurück"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Bearbeiten"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Herunterladen"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Sperrbildschirm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Startbildschirm"</string> <string name="reset" msgid="4945445169532850631">"Zurücksetzen"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Bist du sicher?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Hierdurch werden alle vorgenommenen Änderungen rückgängig gemacht."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Änderungen zurücksetzen?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Änderungen werden nicht gespeichert."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Weitere Hintergründe"</string> </resources> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 931856df..e66c83d3 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Πληροφορίες"</string> <string name="tab_customize" msgid="2533745409174959960">"Προσαρμογή"</string> <string name="tab_effects" msgid="3213606157589233901">"Εφέ"</string> + <string name="tab_share" msgid="6676269624804601227">"Κοινοποίηση"</string> <string name="my_photos" msgid="8613021349284084982">"Οι φωτογραφίες μου"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ρυθμίσεις…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Διαγραφή"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Διαγραφή αυτής της ταπετσαρίας από το τηλέφωνό σας;"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Επεξεργασία"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Να διαγραφεί αυτή η ταπετσαρία από τη συσκευή σας;"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Πίσω"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Επεξεργασία"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Λήψη"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Οθόνη κλειδώματος"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Αρχική οθόνη"</string> <string name="reset" msgid="4945445169532850631">"Επαναφορά"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Είστε βέβαιοι;"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Αυτή η ενέργεια θα επαναφέρει όλες τις αλλαγές που κάνατε."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Να γίνει επαναφορά αλλαγών;"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Οι αλλαγές σας δεν θα αποθηκευτούν"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Περισσότερες ταπετσαρίες"</string> </resources> diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 42ef3030..4e073fb0 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Customise"</string> <string name="tab_effects" msgid="3213606157589233901">"Effects"</string> + <string name="tab_share" msgid="6676269624804601227">"Share"</string> <string name="my_photos" msgid="8613021349284084982">"My Photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Settings…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Delete this wallpaper from your phone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Delete this wallpaper from your device?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Back"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lock screen"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Home screen"</string> <string name="reset" msgid="4945445169532850631">"Reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Are you sure?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"This will reset all changes that you made."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Reset changes?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Your changes won\'t be saved"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"More wallpapers"</string> </resources> diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index 799b6e4c..56b434f6 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -81,10 +81,15 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Customise"</string> <string name="tab_effects" msgid="3213606157589233901">"Effects"</string> + <!-- no translation found for tab_share (6676269624804601227) --> + <skip /> <string name="my_photos" msgid="8613021349284084982">"My Photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Settings…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Delete this wallpaper from your phone?"</string> + <!-- no translation found for edit_live_wallpaper (3132060073690558045) --> + <skip /> + <!-- no translation found for delete_wallpaper_confirmation (1905114562243802354) --> + <skip /> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Back"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -117,8 +122,10 @@ <skip /> <!-- no translation found for reset (4945445169532850631) --> <skip /> - <!-- no translation found for reset_confirmation_dialog_title (3006691785800178536) --> + <!-- no translation found for reset_confirmation_dialog_title (3391905685838213712) --> + <skip /> + <!-- no translation found for reset_confirmation_dialog_message (888669268626289603) --> <skip /> - <!-- no translation found for reset_confirmation_dialog_message (4304013650135221616) --> + <!-- no translation found for more_wallpapers (7585665124282737376) --> <skip /> </resources> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 42ef3030..4e073fb0 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Customise"</string> <string name="tab_effects" msgid="3213606157589233901">"Effects"</string> + <string name="tab_share" msgid="6676269624804601227">"Share"</string> <string name="my_photos" msgid="8613021349284084982">"My Photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Settings…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Delete this wallpaper from your phone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Delete this wallpaper from your device?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Back"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lock screen"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Home screen"</string> <string name="reset" msgid="4945445169532850631">"Reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Are you sure?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"This will reset all changes that you made."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Reset changes?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Your changes won\'t be saved"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"More wallpapers"</string> </resources> diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 42ef3030..4e073fb0 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Customise"</string> <string name="tab_effects" msgid="3213606157589233901">"Effects"</string> + <string name="tab_share" msgid="6676269624804601227">"Share"</string> <string name="my_photos" msgid="8613021349284084982">"My Photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Settings…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Delete this wallpaper from your phone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Delete this wallpaper from your device?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Back"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lock screen"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Home screen"</string> <string name="reset" msgid="4945445169532850631">"Reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Are you sure?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"This will reset all changes that you made."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Reset changes?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Your changes won\'t be saved"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"More wallpapers"</string> </resources> diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml index 7da2e4bd..5d48774e 100644 --- a/res/values-en-rXC/strings.xml +++ b/res/values-en-rXC/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Customize"</string> <string name="tab_effects" msgid="3213606157589233901">"Effects"</string> + <string name="tab_share" msgid="6676269624804601227">"Share"</string> <string name="my_photos" msgid="8613021349284084982">"My Photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Settings…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Delete this wallpaper from your phone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Delete this wallpaper from your device?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Back"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lock screen"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Home screen"</string> <string name="reset" msgid="4945445169532850631">"Reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Are you sure?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"This will reset all changes you made."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Reset changes?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Your changes won\'t be saved"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"More Wallpapers"</string> </resources> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 1cc7c211..98016f34 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -40,7 +40,7 @@ <string name="permission_needed_explanation" msgid="139166837541426823">"Para mostrar el fondo de pantalla actual aquí, <xliff:g id="APP_NAME">%1$s</xliff:g> necesita acceso al almacenamiento de tu dispositivo."</string> <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"Para mostrar el fondo de pantalla actual aquí, Fondos de pantalla necesita acceso al almacenamiento de tu dispositivo.\n\nPara cambiar esta configuración, ve al área de Permisos en la información de la app de Fondos de pantalla."</string> <string name="permission_needed_allow_access_button_label" msgid="1943133660612924306">"Permitir acceso"</string> - <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Fondo de pantalla animado para fondos rotatorios"</string> + <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Fondo animado para fondos rotatorios"</string> <string name="daily_refresh_tile_title" msgid="3270456074558525091">"Fondo de pantalla diario"</string> <string name="daily_refresh_tile_subtitle" msgid="3976682014885446443">"Presiona para activar"</string> <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"El fondo de pantalla cambiará automáticamente todos los días. Para finalizar la configuración, presiona <strong>Definir como fondo de pantalla</strong> en la siguiente pantalla."</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Información"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizar"</string> <string name="tab_effects" msgid="3213606157589233901">"Efectos"</string> + <string name="tab_share" msgid="6676269624804601227">"Compartir"</string> <string name="my_photos" msgid="8613021349284084982">"Mis fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Configuración…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Borrar"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"¿Quieres borrar este fondo de pantalla del teléfono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editar"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"¿Quieres borrar este fondo de pantalla del dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Atrás"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editar"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Descargar"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Pantalla de bloqueo"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Pantalla principal"</string> <string name="reset" msgid="4945445169532850631">"Restablecer"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"¿Confirmas esta acción?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Se restablecerán todos los cambios."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"¿Restablecer los cambios?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"No se guardarán los cambios"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Más fondos de pantalla"</string> </resources> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 822f3153..4a231b9a 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -40,7 +40,7 @@ <string name="permission_needed_explanation" msgid="139166837541426823">"Para mostrar el fondo de pantalla actual aquí, <xliff:g id="APP_NAME">%1$s</xliff:g> necesita acceder al almacenamiento de tu dispositivo."</string> <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"Para mostrar el fondo de pantalla actual, la aplicación Fondos de pantalla necesita acceder al almacenamiento del dispositivo.\n\nPara cambiar esta opción, accede al área Permisos de la información de la aplicación."</string> <string name="permission_needed_allow_access_button_label" msgid="1943133660612924306">"Permitir acceso"</string> - <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Servicio de fondo de pantalla animado para fondos cambiantes"</string> + <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Servicio de fondo animado para fondos cambiantes"</string> <string name="daily_refresh_tile_title" msgid="3270456074558525091">"Fondo de pantalla diario"</string> <string name="daily_refresh_tile_subtitle" msgid="3976682014885446443">"Toca para activar"</string> <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"El fondo de pantalla cambiará automáticamente todos los días. Para finalizar la configuración, toca <strong>Establecer fondo de pantalla</strong> en la siguiente pantalla."</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Información"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizar"</string> <string name="tab_effects" msgid="3213606157589233901">"Efectos"</string> + <string name="tab_share" msgid="6676269624804601227">"Compartir"</string> <string name="my_photos" msgid="8613021349284084982">"Mis fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ajustes…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Eliminar"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"¿Eliminar este fondo de pantalla de tu teléfono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editar"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"¿Eliminar este fondo de pantalla de tu dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Volver"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editar"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Descargar"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Pantalla de bloqueo"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Pantalla de inicio"</string> <string name="reset" msgid="4945445169532850631">"Restablecer"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"¿Seguro que quieres hacerlo?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Se restablecerán todos los cambios que has hecho."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"¿Revertir cambios?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Tus cambios no se guardarán"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Más fondos de pantalla"</string> </resources> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index 4e60dc5d..fbf51770 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Teave"</string> <string name="tab_customize" msgid="2533745409174959960">"Kohandamine"</string> <string name="tab_effects" msgid="3213606157589233901">"Efektid"</string> + <string name="tab_share" msgid="6676269624804601227">"Jagamine"</string> <string name="my_photos" msgid="8613021349284084982">"Minu fotod"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Seaded …"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Kustuta"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Kas soovite taustapildi telefonist kustutada?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Muuda"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Kas kustutada see taustapilt seadmest?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Tagasi"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Muuda"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Laadi alla"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lukustuskuva"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Avakuva"</string> <string name="reset" msgid="4945445169532850631">"Lähtesta"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Kas olete kindel?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"See lähtestab kõik tehtud muudatused."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Kas lähtestada muudatused?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Muudatusi ei salvestata"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Veel taustapilte"</string> </resources> diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index bf5a9f92..85ae1d4d 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informazioa"</string> <string name="tab_customize" msgid="2533745409174959960">"Pertsonalizatu"</string> <string name="tab_effects" msgid="3213606157589233901">"Efektuak"</string> + <string name="tab_share" msgid="6676269624804601227">"Partekatu"</string> <string name="my_photos" msgid="8613021349284084982">"Nire argazkiak"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ezarpenak…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Ezabatu"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Telefonotik ezabatu nahi duzu horma-papera?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editatu"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Horma-papera ezabatu nahi duzu gailutik?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Atzera"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editatu"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Deskargatu"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Pantaila blokeatua"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Hasierako pantaila"</string> <string name="reset" msgid="4945445169532850631">"Berrezarri"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ziur zaude?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Egindako aldaketa guztiak berrezarriko dira."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Aldaketak berrezarri?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Ez dira gordeko aldaketak"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Horma-paper gehiago"</string> </resources> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 3efdf406..fbb7c6c7 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"اطلاعات"</string> <string name="tab_customize" msgid="2533745409174959960">"سفارشی کردن"</string> <string name="tab_effects" msgid="3213606157589233901">"جلوهها"</string> + <string name="tab_share" msgid="6676269624804601227">"همرسانی"</string> <string name="my_photos" msgid="8613021349284084982">"عکسهای من"</string> <string name="configure_wallpaper" msgid="849882179182976621">"تنظیمات…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"حذف"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"این کاغذدیواری از تلفن حذف شود؟"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ویرایش"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"این کاغذدیواری از دستگاهتان حذف شود؟"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"برگشت"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ویرایش"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"بارگیری"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"صفحه قفل"</string> <string name="home_screen_tab" msgid="1080445697837877526">"صفحه اصلی"</string> <string name="reset" msgid="4945445169532850631">"بازنشانی"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"مطمئن هستید؟"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"با این کار، همه تغییرات ایجادشده بازنشانی خواهد شد."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"تغییرات بازنشانی شود؟"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"تغییرات شما ذخیره نمیشود"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"کاغذدیواریهای بیشتر"</string> </resources> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 24671374..2529f990 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Tiedot"</string> <string name="tab_customize" msgid="2533745409174959960">"Personoi"</string> <string name="tab_effects" msgid="3213606157589233901">"Tehosteet"</string> + <string name="tab_share" msgid="6676269624804601227">"Jaa"</string> <string name="my_photos" msgid="8613021349284084982">"Omat kuvat"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Asetukset…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Poista"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Poistetaanko tämä taustakuva puhelimelta?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Muokkaa"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Poistetaanko tämä taustakuva laitteelta?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Takaisin"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Muokkaa"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Lataa"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lukitusnäyttö"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Aloitusnäyttö"</string> <string name="reset" msgid="4945445169532850631">"Nollaa"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Oletko varma?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Tämä nollaa kaikki tekemäsi muutokset."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Nollataanko muutokset?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Muutoksia ei tallenneta"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Lisää taustakuvia"</string> </resources> diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index c4dbddf5..42dd9ba7 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Personnaliser"</string> <string name="tab_effects" msgid="3213606157589233901">"Effets"</string> + <string name="tab_share" msgid="6676269624804601227">"Partager"</string> <string name="my_photos" msgid="8613021349284084982">"Mes photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Paramètres…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Supprimer"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Supprimer ce fond d\'écran de votre téléphone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Modifier"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Supprimer ce fond d\'écran de votre appareil?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Retour"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Modifier"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Télécharger"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Écran de verrouillage"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Écran d\'accueil"</string> <string name="reset" msgid="4945445169532850631">"Réinitialiser"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Voulez-vous vraiment continuer?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Cette action réinitialisera toutes les modifications que vous avez apportées."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Réinitialiser les modifications?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Vos modifications ne seront pas enregistrées"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Plus de fonds d\'écran"</string> </resources> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index a3802c20..be35226d 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informations"</string> <string name="tab_customize" msgid="2533745409174959960">"Personnaliser"</string> <string name="tab_effects" msgid="3213606157589233901">"Effets"</string> + <string name="tab_share" msgid="6676269624804601227">"Partager"</string> <string name="my_photos" msgid="8613021349284084982">"Mes photos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Paramètres…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Supprimer"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Supprimer ce fond d\'écran de votre téléphone ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Modifier"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Supprimer ce fond d\'écran de votre appareil ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Retour"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Modifier"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Télécharger"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Écran de verrouillage"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Écran d\'accueil"</string> <string name="reset" msgid="4945445169532850631">"Réinitialiser"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Voulez-vous vraiment continuer ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Cela réinitialisera toutes les modifications que vous avez effectuées."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Réinitialiser modifications ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Vos modifications ne seront pas enregistrées"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Autres fonds d\'écran"</string> </resources> diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index fd4f05dd..6b7adbab 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -21,7 +21,7 @@ <!-- no translation found for app_name (8773648973927541493) --> <skip /> <string name="select_wallpaper_label" msgid="6989581259339646085">"Categorías de fondos de pantalla"</string> - <string name="set_wallpaper_button_text" msgid="4426286890442731310">"Establecer fondo de pantalla"</string> + <string name="set_wallpaper_button_text" msgid="4426286890442731310">"Fixar fondo de pantalla"</string> <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"Establecendo fondo de pantalla…"</string> <string name="try_again" msgid="8278874823700921234">"Tentar de novo"</string> <string name="set_wallpaper_error_message" msgid="6819986999041085130">"Non se puido establecer o fondo de pantalla."</string> @@ -77,14 +77,16 @@ <string name="center_wallpaper_position" msgid="4166894762352288883">"Centro"</string> <string name="center_crop_wallpaper_position" msgid="1681980019815343348">"Recortar no centro"</string> <string name="stretch_wallpaper_position" msgid="5002680983147456935">"Estirar"</string> - <string name="preview" msgid="1774602101743861071">"Mostrar vista previa"</string> + <string name="preview" msgid="1774602101743861071">"Vista previa"</string> <string name="tab_info" msgid="818614080690111416">"Información"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizar"</string> <string name="tab_effects" msgid="3213606157589233901">"Efectos"</string> + <string name="tab_share" msgid="6676269624804601227">"Compartir"</string> <string name="my_photos" msgid="8613021349284084982">"As miñas fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Configuración…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Eliminar"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Queres eliminar este fondo de pantalla do teu teléfono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editar"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Queres eliminar este fondo de pantalla do dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Atrás"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editar"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Descargar"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Pantalla de bloqueo"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Pantalla de inicio"</string> <string name="reset" msgid="4945445169532850631">"Restablecer"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Seguro que queres continuar?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Restableceranse todos os cambios que fixeses."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Queres restablecer os cambios?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Non se gardarán os cambios"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Máis fondos de pantalla"</string> </resources> diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index def244f6..c92893fc 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"માહિતી"</string> <string name="tab_customize" msgid="2533745409174959960">"કસ્ટમાઇઝ કરો"</string> <string name="tab_effects" msgid="3213606157589233901">"ઇફેક્ટ"</string> + <string name="tab_share" msgid="6676269624804601227">"શેર કરો"</string> <string name="my_photos" msgid="8613021349284084982">"મારા ફોટા"</string> <string name="configure_wallpaper" msgid="849882179182976621">"સેટિંગ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ડિલીટ કરો"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"તમારા ફોનમાંથી આ વૉલપેપર ડિલીટ કરીએ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ફેરફાર કરો"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"તમારા ડિવાઇસમાંથી આ વૉલપેપર ડિલીટ કરીએ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"પાછળ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ફેરફાર કરો"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ડાઉનલોડ કરો"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"લૉક સ્ક્રીન"</string> <string name="home_screen_tab" msgid="1080445697837877526">"હોમ સ્ક્રીન"</string> <string name="reset" msgid="4945445169532850631">"રીસેટ કરો"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ખરેખર?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"તમે કરેલા બધા ફેરફારો, આનાથી રીસેટ થશે."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ફેરફારો રીસેટ કરીએ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"તમારા ફેરફારો સાચવવામાં આવશે નહીં"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"વધુ વૉલપેપર"</string> </resources> diff --git a/res/values-h1220dp/dimens.xml b/res/values-h1220dp/dimens.xml index 75ec8ff8..c686638f 100644 --- a/res/values-h1220dp/dimens.xml +++ b/res/values-h1220dp/dimens.xml @@ -21,4 +21,8 @@ <!-- Dimensions for GridFragment. --> <dimen name="preview_card_vertical_bias">0</dimen> + + <!-- Clipping of the home screen overlay --> + <dimen name="home_screen_overlay_top_clipping">0dp</dimen> + <dimen name="home_screen_overlay_bottom_clipping">100dp</dimen> </resources>
\ No newline at end of file diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 59133d11..7b533255 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"जानकारी"</string> <string name="tab_customize" msgid="2533745409174959960">"पसंद के मुताबिक बनाएं"</string> <string name="tab_effects" msgid="3213606157589233901">"इफ़ेक्ट"</string> + <string name="tab_share" msgid="6676269624804601227">"शेयर करें"</string> <string name="my_photos" msgid="8613021349284084982">"मेरी फ़ोटो"</string> <string name="configure_wallpaper" msgid="849882179182976621">"सेटिंग…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"मिटाएं"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"क्या आप अपने फ़ोन से यह वॉलपेपर मिटाना चाहते हैं?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"बदलाव करें"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"क्या आपको अपने डिवाइस से यह वॉलपेपर मिटाना है?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"वापस जाएं"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"बदलाव करें"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"डाउनलोड करें"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"लॉक स्क्रीन"</string> <string name="home_screen_tab" msgid="1080445697837877526">"होम स्क्रीन"</string> <string name="reset" msgid="4945445169532850631">"रीसेट करें"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"क्या आपको बदलाव रीसेट करने हैं?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ऐसा करने पर, आपके किए हुए सभी बदलाव रीसेट कर दिए जाएंगे."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"क्या आपको बदलाव रीसेट करना है?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"आपके बदलाव सेव नहीं किए जाएंगे"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ज़्यादा वॉलपेपर"</string> </resources> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index dd87a58c..75884f78 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacije"</string> <string name="tab_customize" msgid="2533745409174959960">"Prilagodba"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekti"</string> + <string name="tab_share" msgid="6676269624804601227">"Podijeli"</string> <string name="my_photos" msgid="8613021349284084982">"Moje fotografije"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Postavke…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Izbriši"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Želite li izbrisati tu pozadinu s telefona?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Uredi"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Izbrisati ovu pozadinu s uređaja?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Natrag"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Uredi"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Preuzmi"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Zaključan zaslon"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Početni zaslon"</string> <string name="reset" msgid="4945445169532850631">"Poništi"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Jeste li sigurni?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Time će se poništiti sve promjene koje ste unijeli."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Poništiti promjene?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Promjene se neće spremiti"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Više pozadina"</string> </resources> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index e9422558..993cecdd 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Információ"</string> <string name="tab_customize" msgid="2533745409174959960">"Személyre szabás"</string> <string name="tab_effects" msgid="3213606157589233901">"Effektek"</string> + <string name="tab_share" msgid="6676269624804601227">"Megosztás"</string> <string name="my_photos" msgid="8613021349284084982">"Saját fotóim"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Beállítások…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Törlés"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Törli ezt a háttérképet a telefonjáról?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Szerkesztés"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Törli ezt a háttérképet az eszközről?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Vissza"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Módosítás"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Letöltés"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lezárási képernyő"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Kezdőképernyő"</string> <string name="reset" msgid="4945445169532850631">"Alaphelyzet"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Biztos benne?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ez visszaállítja az Ön által végzett összes módosítást."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Visszaállítja a módosításokat?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"A módosítások nem lesznek mentve"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"További hátterek"</string> </resources> diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index 12e2bfed..6924d9d3 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Տեղեկություն"</string> <string name="tab_customize" msgid="2533745409174959960">"Կարգավորել"</string> <string name="tab_effects" msgid="3213606157589233901">"Էֆեկտներ"</string> + <string name="tab_share" msgid="6676269624804601227">"Կիսվեք"</string> <string name="my_photos" msgid="8613021349284084982">"Իմ լուսանկարները"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Կարգավորումներ"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Ջնջել"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Ջնջե՞լ այս պաստառը հեռախոսից։"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Փոփոխել"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Ջնջե՞լ այս պաստառը ձեր սարքից։"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Հետ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Փոփոխել"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Ներբեռնել"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Կողպէկրան"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Հիմնական էկրան"</string> <string name="reset" msgid="4945445169532850631">"Զրոյացնել"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Համոզվա՞ծ եք"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ձեր կատարած բոլոր փոփոխությունները կզրոյացվեն։"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Չեղարկե՞լ փոփոխությունները"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Ձեր փոփոխությունները չեն պահվի"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Այլ պաստառներ"</string> </resources> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 3d00b199..95e1080f 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Info"</string> <string name="tab_customize" msgid="2533745409174959960">"Sesuaikan"</string> <string name="tab_effects" msgid="3213606157589233901">"Efek"</string> + <string name="tab_share" msgid="6676269624804601227">"Bagikan"</string> <string name="my_photos" msgid="8613021349284084982">"Foto Saya"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Setelan…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Hapus"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Hapus wallpaper ini dari ponsel Anda?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Hapus wallpaper ini dari perangkat?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Kembali"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Layar kunci"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Layar utama"</string> <string name="reset" msgid="4945445169532850631">"Reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Yakin?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Tindakan ini akan mereset semua perubahan yang Anda lakukan."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Reset perubahan?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Perubahan tidak akan disimpan"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Wallpaper Lainnya"</string> </resources> diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index bfa6d9a6..8880f66f 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Upplýsingar"</string> <string name="tab_customize" msgid="2533745409174959960">"Sérsníða"</string> <string name="tab_effects" msgid="3213606157589233901">"Áhrif"</string> + <string name="tab_share" msgid="6676269624804601227">"Deila"</string> <string name="my_photos" msgid="8613021349284084982">"Mínar myndir"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Stillingar…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Eyða"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Viltu eyða þessu veggfóðri úr símanum?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Breyta"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Eyða þessu veggfóðri úr tækinu?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Til baka"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Breyta"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Sækja"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Lásskjár"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Heimaskjár"</string> <string name="reset" msgid="4945445169532850631">"Endurstilla"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ertu viss?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Þetta mun endurstilla allar breytingarnar sem þú gerðir."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Endurstilla breytingar?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Breytingarnar verða ekki vistaðar"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Fleiri veggfóður"</string> </resources> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 737d6b0a..003b354c 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -81,14 +81,16 @@ <string name="tab_info" msgid="818614080690111416">"Informazioni"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizza"</string> <string name="tab_effects" msgid="3213606157589233901">"Effetti"</string> + <string name="tab_share" msgid="6676269624804601227">"Condividi"</string> <string name="my_photos" msgid="8613021349284084982">"Le mie foto"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Impostazioni…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Elimina"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vuoi eliminare questo sfondo dal telefono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Modifica"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Eliminare questo sfondo dal tuo dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Indietro"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Modifica"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Scarica"</string> - <string name="bottom_action_bar_slideshow_wallpaper" msgid="509770525179533154">"Sfondo slideshow"</string> + <string name="bottom_action_bar_slideshow_wallpaper" msgid="509770525179533154">"Sfondo presentazione"</string> <string name="bottom_action_bar_apply" msgid="2983308349819178932">"Applica"</string> <string name="accessibility_preview_pager" msgid="1839869637405028575">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string> <string name="next_page_content_description" msgid="6268461446679584152">"Avanti"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Schermata di blocco"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Schermata Home"</string> <string name="reset" msgid="4945445169532850631">"Reimposta"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Confermi?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Verranno reimpostate tutte le modifiche apportate."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vuoi reimpostare le modifiche?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Le modifiche non verranno salvate"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Altri sfondi"</string> </resources> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 7fa7be07..d2f7715f 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"מידע"</string> <string name="tab_customize" msgid="2533745409174959960">"התאמה אישית"</string> <string name="tab_effects" msgid="3213606157589233901">"אפקטים"</string> + <string name="tab_share" msgid="6676269624804601227">"שיתוף"</string> <string name="my_photos" msgid="8613021349284084982">"התמונות שלי"</string> <string name="configure_wallpaper" msgid="849882179182976621">"הגדרות…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"מחיקה"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"למחוק את הטפט הזה מהטלפון?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"עריכה"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"למחוק את הטפט הזה מהמכשיר?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"חזרה"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"עריכה"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"הורדה"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"מסך נעילה"</string> <string name="home_screen_tab" msgid="1080445697837877526">"מסך הבית"</string> <string name="reset" msgid="4945445169532850631">"איפוס"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"להמשיך?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"הפעולה הזו תאפס את כל השינויים שביצעת."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"לאפס את השינויים?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"השינויים שביצעת לא יישמרו"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"טפטים נוספים"</string> </resources> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index fdf14e1c..a53499d6 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"情報"</string> <string name="tab_customize" msgid="2533745409174959960">"カスタマイズ"</string> <string name="tab_effects" msgid="3213606157589233901">"効果"</string> + <string name="tab_share" msgid="6676269624804601227">"共有"</string> <string name="my_photos" msgid="8613021349284084982">"マイ フォト"</string> <string name="configure_wallpaper" msgid="849882179182976621">"設定…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"削除"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"スマートフォンからこの壁紙を削除しますか?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"編集"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"この壁紙をデバイスから削除しますか?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"戻る"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"編集"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ダウンロード"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ロック画面"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ホーム画面"</string> <string name="reset" msgid="4945445169532850631">"リセット"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"本当によろしいですか?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"行った変更はすべてリセットされます。"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"変更をリセットしますか?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"変更内容は保存されません"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"その他の壁紙"</string> </resources> diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index dcc0de23..ca9e79ba 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ინფორმაცია"</string> <string name="tab_customize" msgid="2533745409174959960">"მორგება"</string> <string name="tab_effects" msgid="3213606157589233901">"ეფექტები"</string> + <string name="tab_share" msgid="6676269624804601227">"გაზიარება"</string> <string name="my_photos" msgid="8613021349284084982">"ჩემი ფოტოები"</string> <string name="configure_wallpaper" msgid="849882179182976621">"პარამეტრები..."</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"წაშლა"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"წაიშალოს ეს ფონი თქვენი ტელეფონიდან?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"რედაქტირება"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"წაიშალოს ეს ფონი თქვენი მოწყობილობიდან?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"უკან"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"რედაქტირება"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ჩამოტვირთვა"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ჩაკეტილი ეკრანი"</string> <string name="home_screen_tab" msgid="1080445697837877526">"მთავარი ეკრანი"</string> <string name="reset" msgid="4945445169532850631">"გადაყენება"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"დარწმუნებული ხართ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ამით გადაყენდება თქვენ მიერ განხორციელებული ყველა ცვლილება."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ცვლილებების გადაყენება?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"თქვენი ცვლილებები არ შეინახება"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"მეტი ფონი"</string> </resources> diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index eb78e7ba..81265df7 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Ақпарат"</string> <string name="tab_customize" msgid="2533745409174959960">"Реттеу"</string> <string name="tab_effects" msgid="3213606157589233901">"Әсерлер"</string> + <string name="tab_share" msgid="6676269624804601227">"Бөлісу"</string> <string name="my_photos" msgid="8613021349284084982">"Суреттерім"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Параметрлер…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Жою"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Бұл тұсқағаз телефоннан жойылсын ба?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Өзгерту"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Осы тұсқағазды құрылғыдан өшіру керек пе?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Артқа"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Өзгерту"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Жүктеп алу"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Экранды құлыптау"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Негізгі экран"</string> <string name="reset" msgid="4945445169532850631">"Қайта орнату"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Сенімдісіз бе?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Жасалған барлық өзгеріс қайтарылады."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Өзгертулерді қайтару керек пе?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Өзгертулер сақталмайды."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Қосымша тұсқағаздар"</string> </resources> diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index 86c8d552..abd17195 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ព័ត៌មាន"</string> <string name="tab_customize" msgid="2533745409174959960">"ប្ដូរតាមបំណង"</string> <string name="tab_effects" msgid="3213606157589233901">"បែបផែន"</string> + <string name="tab_share" msgid="6676269624804601227">"ចែករំលែក"</string> <string name="my_photos" msgid="8613021349284084982">"រូបថតខ្ញុំ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ការកំណត់…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"លុប"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"លុបផ្ទាំងរូបភាពនេះពីទូរសព្ទរបស់អ្នកដែរទេ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"កែ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"លុបផ្ទាំងរូបភាពនេះចេញពីឧបករណ៍របស់អ្នកឬ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ថយក្រោយ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"កែ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ទាញយក"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"អេក្រង់ចាក់សោ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"អេក្រង់ដើម"</string> <string name="reset" msgid="4945445169532850631">"កំណត់ឡើងវិញ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"តើអ្នកប្រាកដដែរទេ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ការធ្វើបែបនេះនឹងកំណត់ការផ្លាស់ប្ដូរទាំងអស់ដែលអ្នកបានធ្វើឡើងវិញ។"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"កំណត់ការផ្លាស់ប្ដូរឡើងវិញឬ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ការផ្លាស់ប្ដូររបស់អ្នកនឹងមិនត្រូវបានរក្សាទុកទេ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ផ្ទាំងរូបភាពច្រើនទៀត"</string> </resources> diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 91c92fc9..d64ccd3b 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -54,7 +54,7 @@ <string name="next_wallpaper" msgid="3911873152952596232">"ಮುಂದಿನ ವಾಲ್ಪೇಪರ್"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"ಈ ಸಾಧನದಲ್ಲಿ ವಾಲ್ಪೇಪರ್ ಹೊಂದಿಸುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"ನಿಮ್ಮ ಸಾಧನ ನಿರ್ವಾಹಕರಿಂದ ವಾಲ್ಪೇಪರ್ ಹೊಂದಿಸುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> - <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"ವಾಲ್ಪೇಪರ್ ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಹೊಂದಿಸಲಾಗಿದೆ"</string> + <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"ವಾಲ್ಪೇಪರ್ ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಸೆಟ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"ವಾಲ್ಪೇಪರ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ನಿಮಗೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕ ಅಗತ್ಯವಿದೆ. ಇಂಟರ್ನೆಟ್ಗೆ ಸಂಪರ್ಕಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"ಪ್ರಸ್ತುತವಾಗಿ ಮುಖಪುಟ ಪರದೆಯ ವಾಲ್ಪೇಪರ್ ಥಂಬ್ನೇಲ್ ಹೊಂದಿಸಿ"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"ಪ್ರಸ್ತುತವಾಗಿ ಲಾಕ್ ಪರದೆಯ ವಾಲ್ಪೇಪರ್ ಥಂಬ್ನೇಲ್ ಹೊಂದಿಸಿ"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ಮಾಹಿತಿ"</string> <string name="tab_customize" msgid="2533745409174959960">"ಕಸ್ಟಮೈಜ್ ಮಾಡಿ"</string> <string name="tab_effects" msgid="3213606157589233901">"ಎಫೆಕ್ಟ್ಗಳು"</string> + <string name="tab_share" msgid="6676269624804601227">"ಹಂಚಿಕೊಳ್ಳಿ"</string> <string name="my_photos" msgid="8613021349284084982">"ನನ್ನ ಫೋಟೋಗಳು"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ಸೆಟ್ಟಿಂಗ್ಗಳು..."</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ಅಳಿಸಿ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ನಿಮ್ಮ ಫೋನ್ನಿಂದ ಈ ವಾಲ್ಪೇಪರ್ ಅನ್ನು ಅಳಿಸುವುದೇ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ಎಡಿಟ್ ಮಾಡಿ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ನಿಮ್ಮ ಸಾಧನದಿಂದ ಈ ವಾಲ್ಪೇಪರ್ ಅಳಿಸಬೇಕೆ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ಹಿಂದೆ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ಎಡಿಟ್ ಮಾಡಿ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ಡೌನ್ಲೋಡ್"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಮಾಡಿ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ಹೋಮ್ ಸ್ಕ್ರೀನ್"</string> <string name="reset" msgid="4945445169532850631">"ರೀಸೆಟ್ ಮಾಡಿ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ರೀಸೆಟ್ ಮಾಡಲು ಬಯಸುತ್ತೀರಾ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ಇದು ನೀವು ಮಾಡಿದ ಎಲ್ಲಾ ಬದಲಾವಣೆಗಳನ್ನು ರೀಸೆಟ್ ಮಾಡುತ್ತದೆ."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ಬದಲಾವಣೆಗಳನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ನಿಮ್ಮ ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ಇನ್ನಷ್ಟು ವಾಲ್ಪೇಪರ್ಗಳು"</string> </resources> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 6100cf43..4f8de84d 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"정보"</string> <string name="tab_customize" msgid="2533745409174959960">"맞춤설정"</string> <string name="tab_effects" msgid="3213606157589233901">"효과"</string> + <string name="tab_share" msgid="6676269624804601227">"공유"</string> <string name="my_photos" msgid="8613021349284084982">"내 사진"</string> <string name="configure_wallpaper" msgid="849882179182976621">"설정…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"삭제"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"휴대전화에서 이 배경화면을 삭제하시겠습니까?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"수정"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"기기에서 이 배경화면을 삭제하시겠습니까?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"뒤로"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"수정"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"다운로드"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"잠금 화면"</string> <string name="home_screen_tab" msgid="1080445697837877526">"홈 화면"</string> <string name="reset" msgid="4945445169532850631">"초기화"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"계속하시겠습니까?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"이렇게 하면 모든 변경사항이 재설정됩니다."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"변경사항을 재설정하시겠습니까?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"변경사항이 저장되지 않습니다."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"배경화면 더보기"</string> </resources> diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index e3bb2987..5d46a74f 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -21,7 +21,7 @@ <!-- no translation found for app_name (8773648973927541493) --> <skip /> <string name="select_wallpaper_label" msgid="6989581259339646085">"Тушкагаз категориялары"</string> - <string name="set_wallpaper_button_text" msgid="4426286890442731310">"Тушкагаз орнотуу"</string> + <string name="set_wallpaper_button_text" msgid="4426286890442731310">"Тушкагаз коюу"</string> <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"Тушкагаз орнотулууда…"</string> <string name="try_again" msgid="8278874823700921234">"Кайталоо"</string> <string name="set_wallpaper_error_message" msgid="6819986999041085130">"Тушкагаз орнотулбай жатат."</string> @@ -43,13 +43,13 @@ <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Жандуу тушкагаз кызматы тушкагаздарды алмаштырат"</string> <string name="daily_refresh_tile_title" msgid="3270456074558525091">"Күнүмдүк тушкагаз"</string> <string name="daily_refresh_tile_subtitle" msgid="3976682014885446443">"Күйгүзүү үчүн таптап коюңуз"</string> - <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"Тушкагаз күн сайын автоматтык түрдө алмашып турат. Жөндөөнү аягына чыгаруу үчүн кийинки экрандан <strong>Тушкагаз орнотуу</strong> баскычын таптап коюңуз."</string> + <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"Тушкагаз күн сайын автоматтык түрдө алмашып турат. Жөндөөнү аягына чыгаруу үчүн кийинки экрандан <strong>Тушкагаз коюу</strong> баскычын таптап коюңуз."</string> <string name="start_rotation_dialog_wifi_only_option_message" msgid="3126269859713666225">"Келечекте тушкагаздар Wi-Fi аркылуу гана жүктөлүп алынсын"</string> <string name="start_rotation_dialog_continue" msgid="276678987852274872">"Улантуу"</string> <string name="start_rotation_progress_message" msgid="7872623873682262083">"Биринчи тушкагаз жүктөлүп алынууда…"</string> - <string name="start_rotation_error_message" msgid="3053799836719618972">"Биринчи тушкагаз жүктөлүп алынбай жатат. Тармак жөндөөлөрүңүздү текшерип, кайталап көрүңүз."</string> + <string name="start_rotation_error_message" msgid="3053799836719618972">"Биринчи тушкагаз жүктөлүп алынбай жатат. Тармак параметрлериңизди текшерип, кайталап көрүңүз."</string> <string name="start_rotation_dialog_body" msgid="7903554799046364916">"Тушкагаз күн сайын автоматтык түрдө алмашып турат"</string> - <string name="settings_button_label" msgid="8724734130079207955">"Жөндөөлөр"</string> + <string name="settings_button_label" msgid="8724734130079207955">"Параметрлер"</string> <string name="explore" msgid="7468719504199497281">"Изилдөө"</string> <string name="next_wallpaper" msgid="3911873152952596232">"Кийинки тушкагаз"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"Бул түзмөктө тушкагазды жөндөө өчүрүлгөн"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Маалымат"</string> <string name="tab_customize" msgid="2533745409174959960">"Ыңгайлаштыруу"</string> <string name="tab_effects" msgid="3213606157589233901">"Кубулуштар"</string> + <string name="tab_share" msgid="6676269624804601227">"Бөлүшүү"</string> <string name="my_photos" msgid="8613021349284084982">"Сүрөттөрүм"</string> - <string name="configure_wallpaper" msgid="849882179182976621">"Жөндөөлөр…"</string> + <string name="configure_wallpaper" msgid="849882179182976621">"Параметрлер…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Жок кылуу"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Бул тушкагаз телефонуңуздан өчүрүлсүнбү?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Түзөтүү"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Бул тушкагаз түзмөгүңүздөн өчүрүлсүнбү?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Артка"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Түзөтүү"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Жүктөп алуу"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Экранды кулпулоо"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Башкы экран"</string> <string name="reset" msgid="4945445169532850631">"Баштапкы абалга келтирүү"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Чын элеби?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ушуну менен бардык өзгөртүүлөр баштапкы абалга келтирилет."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Өзгөртүүлөр жоюлсунбу?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Өзгөртүүлөрүңүз сакталбайт"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Дагы башка тушкагаздар"</string> </resources> diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml index 82d5d5c5..57d23bd1 100644 --- a/res/values-lo/strings.xml +++ b/res/values-lo/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ຂໍ້ມູນ"</string> <string name="tab_customize" msgid="2533745409174959960">"ປັບແຕ່ງ"</string> <string name="tab_effects" msgid="3213606157589233901">"ເອັບເຟັກ"</string> + <string name="tab_share" msgid="6676269624804601227">"ແບ່ງປັນ"</string> <string name="my_photos" msgid="8613021349284084982">"ຮູບພາບຂອງຂ້ອຍ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ການຕັ້ງຄ່າ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ລຶບອອກ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ລຶບຮູບພື້ນຫຼັງນີ້ອອກຈາກໂທລະສັບຂອງທ່ານບໍ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ແກ້ໄຂ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ລຶບຮູບພື້ນຫຼັງນີ້ອອກຈາກອຸປະກອນຂອງທ່ານບໍ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ກັບຄືນ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ແກ້ໄຂ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ດາວໂຫຼດ"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ໜ້າຈໍລັອກ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ໂຮມສະກຣີນ"</string> <string name="reset" msgid="4945445169532850631">"ຣີເຊັດ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ທ່ານແນ່ໃຈບໍ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ນີ້ຈະຣີເຊັດການປ່ຽນແປງທັງໝົດທີ່ທ່ານເຮັດ."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ຣີເຊັດການປ່ຽນແປງບໍ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ການປ່ຽນແປງຂອງທ່ານຈະບໍ່ຖືກບັນທຶກ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ຮູບພື້ນຫຼັງເພີ່ມເຕີມ"</string> </resources> diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index b4e4bd57..2fe4e4af 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacija"</string> <string name="tab_customize" msgid="2533745409174959960">"Tinkinimas"</string> <string name="tab_effects" msgid="3213606157589233901">"Efektai"</string> + <string name="tab_share" msgid="6676269624804601227">"Bendrinti"</string> <string name="my_photos" msgid="8613021349284084982">"Mano nuotraukos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Nustatymai…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Ištrinti"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Ištrinti šį ekrano foną iš telefono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Redaguoti"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Ištrinti šį ekrano foną iš įrenginio?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Atgal"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Redaguoti"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Atsisiųsti"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Užrakinimo ekranas"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Pagrindinis ekranas"</string> <string name="reset" msgid="4945445169532850631">"Nust. iš n."</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ar tikrai norite tai padaryti?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Bus iš naujo nustatyti visi atlikti pakeitimai."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Nustatyti pakeitimus iš naujo?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Pakeitimai nebus išsaugoti"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Daugiau darbalaukio fonų"</string> </resources> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index c39c931a..5a632e62 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informācija"</string> <string name="tab_customize" msgid="2533745409174959960">"Pielāgošana"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekti"</string> + <string name="tab_share" msgid="6676269624804601227">"Kopīgot"</string> <string name="my_photos" msgid="8613021349284084982">"Mani fotoattēli"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Iestatījumi…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Dzēst"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vai dzēst šo fona tapeti no tālruņa?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Rediģēt"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vai dzēst šo fona tapeti no jūsu ierīces?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Atpakaļ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Rediģēt"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Lejupielādēt"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Bloķēšanas ekrāns"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Sākuma ekrāns"</string> <string name="reset" msgid="4945445169532850631">"Atiestatīt"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Vai esat pārliecināts?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Tādējādi tiks atiestatītas visas jūsu veiktās izmaiņas."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vai atiestatīt izmaiņas?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Jūsu veiktās izmaiņas netiks saglabātas."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Citas tapetes"</string> </resources> diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 727d1495..d2e9df2b 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Информации"</string> <string name="tab_customize" msgid="2533745409174959960">"Приспособување"</string> <string name="tab_effects" msgid="3213606157589233901">"Ефекти"</string> + <string name="tab_share" msgid="6676269624804601227">"Сподели"</string> <string name="my_photos" msgid="8613021349284084982">"Мои фотографии"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Поставки…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Избриши"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Да се избрише тапетов од телефонот?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Изменете"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Да се избрише овој тапет од уредот?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Измени"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Преземи"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Заклучување екран"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Почетен екран"</string> <string name="reset" msgid="4945445169532850631">"Ресетирај"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Дали сте сигурни?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ова ќе ги ресетира сите извршени промени."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Да се ресетираат промените?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Промените нема да се зачуваат"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Повеќе тапети"</string> </resources> diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index b69d425b..3cc7f45f 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"വിവരം"</string> <string name="tab_customize" msgid="2533745409174959960">"ഇഷ്ടാനുസൃതമാക്കുക"</string> <string name="tab_effects" msgid="3213606157589233901">"ഇഫക്റ്റുകൾ"</string> + <string name="tab_share" msgid="6676269624804601227">"പങ്കിടുക"</string> <string name="my_photos" msgid="8613021349284084982">"എന്റെ ഫോട്ടോകൾ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ക്രമീകരണം…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ഇല്ലാതാക്കുക"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വാൾപേപ്പർ ഇല്ലാതാക്കണോ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"എഡിറ്റ് ചെയ്യുക"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ഉപകരണത്തിൽ നിന്ന് ഈ വാൾപേപ്പർ ഇല്ലാതാക്കണോ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"മടങ്ങുക"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"എഡിറ്റ് ചെയ്യുക"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ഡൗൺലോഡ് ചെയ്യുക"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"സ്ക്രീൻ ലോക്ക് ചെയ്യുക"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ഹോം സ്ക്രീൻ"</string> <string name="reset" msgid="4945445169532850631">"റീസെറ്റ് ചെയ്യൂ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ഉറപ്പാണോ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"നിങ്ങൾ വരുത്തിയ മാറ്റങ്ങളെല്ലാം ഇത് റീസെറ്റ് ചെയ്യും."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"മാറ്റങ്ങൾ റീസെറ്റ് ചെയ്യണോ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"നിങ്ങളുടെ മാറ്റങ്ങൾ സംരക്ഷിക്കില്ല"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"കൂടുതൽ വാൾപേപ്പറുകൾ"</string> </resources> diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml index 87590b51..bbfa0384 100644 --- a/res/values-mn/strings.xml +++ b/res/values-mn/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Мэдээлэл"</string> <string name="tab_customize" msgid="2533745409174959960">"Өөрчлөх"</string> <string name="tab_effects" msgid="3213606157589233901">"Эффект"</string> + <string name="tab_share" msgid="6676269624804601227">"Хуваалцах"</string> <string name="my_photos" msgid="8613021349284084982">"Миний Зураг"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Тохиргоо…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Устгах"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Энэ дэлгэцийн зургийг утаснаасаа устгах уу?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Засах"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Энэ дэлгэцийн зургийг төхөөрөмжөөсөө устгах уу?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Буцах"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Засах"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Татах"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Түгжигдсэн дэлгэц"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Үндсэн нүүр"</string> <string name="reset" msgid="4945445169532850631">"Шинэчлэх"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ta итгэлтэй байна уу?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Энэ нь таны хийсэн бүх өөрчлөлтийг шинэчилнэ."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Өөрчлөлтийг шинэчлэх үү?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Таны өөрчлөлтийг хадгалахгүй"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Дэлгэцийн бусад зураг"</string> </resources> diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 7f4c6c5a..c4a7c852 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"माहिती"</string> <string name="tab_customize" msgid="2533745409174959960">"कस्टमाइझ करा"</string> <string name="tab_effects" msgid="3213606157589233901">"इफेक्ट"</string> + <string name="tab_share" msgid="6676269624804601227">"शेअर करा"</string> <string name="my_photos" msgid="8613021349284084982">"माझे फोटो"</string> <string name="configure_wallpaper" msgid="849882179182976621">"सेटिंग्ज…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"हटवा"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"तुमच्या फोनवरून हा वॉलपेपर हटवायचा आहे का?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"संपादित करा"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"तुमच्या डिव्हाइसवरून हा वॉलपेपर हटवायचा आहे का?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"मागे जा"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"संपादित करा"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"डाउनलोड करा"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"लॉक स्क्रीन"</string> <string name="home_screen_tab" msgid="1080445697837877526">"मुख्य स्क्रीन"</string> <string name="reset" msgid="4945445169532850631">"रीसेट करा"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"तुमची खात्री आहे का?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"यामुळे तुम्ही केलेले सर्व बदल रीसेट होतील."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"बदल रीसेट करायचे आहेत का?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"तुमचे बदल सेव्ह केले जाणार नाहीत"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"आणखी वॉलपेपर"</string> </resources> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index 1cdccfa8..496be53d 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Maklumat"</string> <string name="tab_customize" msgid="2533745409174959960">"Sesuaikan"</string> <string name="tab_effects" msgid="3213606157589233901">"Kesan"</string> + <string name="tab_share" msgid="6676269624804601227">"Kongsi"</string> <string name="my_photos" msgid="8613021349284084982">"Foto Saya"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Tetapan..."</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Padam"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Padamkan kertas dinding ini daripada telefon anda?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Padamkan hiasan latar ini daripada peranti anda?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Kembali"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Muat turun"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Skrin kunci"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Skrin utama"</string> <string name="reset" msgid="4945445169532850631">"Tetapkan semula"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Anda pasti?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Tindakan ini akan menetapkan semula semua perubahan yang telah dibuat."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Tetapkan semula perubahan?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Perubahan anda tidak akan disimpan"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Lagi Hiasan Latar"</string> </resources> diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index a3e5f268..64649bde 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"အချက်အလက်"</string> <string name="tab_customize" msgid="2533745409174959960">"စိတ်ကြိုက်ပြုလုပ်ရန်"</string> <string name="tab_effects" msgid="3213606157589233901">"အထူးပြုလုပ်ချက်များ"</string> + <string name="tab_share" msgid="6676269624804601227">"မျှဝေရန်"</string> <string name="my_photos" msgid="8613021349284084982">"ကျွန်ုပ်၏ဓာတ်ပုံများ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ဆက်တင်များ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ဖျက်ရန်"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ဤနောက်ခံပုံကို သင့်ပင်မစာမျက်နှာမှ ဖျက်ပစ်မလား။"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"တည်းဖြတ်ရန်"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ဤနောက်ခံကို သင့်စက်မှ ဖျက်မလား။"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"နောက်သို့"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ပြင်ဆင်ရန်"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ဒေါင်းလုဒ်လုပ်ရန်"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"လော့ခ်မျက်နှာပြင်"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ပင်မစာမျက်နှာ"</string> <string name="reset" msgid="4945445169532850631">"ပြင်ဆင်ရန်"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"သေချာပါသလား။"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"၎င်းက သင့်အပြောင်းအလဲအားလုံးကို ပြင်ဆင်သတ်မှတ်မည်။"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"အပြောင်းအလဲများ ပြန်သတ်မှတ်မလား။"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"သင့်ပြောင်းလဲမှုများအား သိမ်းမည် မဟုတ်ပါ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"နောက်ထပ်နောက်ခံများ"</string> </resources> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 9da3e428..66722dbd 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informasjon"</string> <string name="tab_customize" msgid="2533745409174959960">"Tilpass"</string> <string name="tab_effects" msgid="3213606157589233901">"Effekter"</string> + <string name="tab_share" msgid="6676269624804601227">"Del"</string> <string name="my_photos" msgid="8613021349284084982">"Mine bilder"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Innstillinger"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Slett"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vil du slette denne bakgrunnen fra telefonen din?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Rediger"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vil du slette denne bakgrunnen fra enheten?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Tilbake"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Endre"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Last ned"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Låseskjerm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Startskjerm"</string> <string name="reset" msgid="4945445169532850631">"Tilbakestill"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Er du sikker?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Dette tilbakestiller alle endringene du har gjort."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vil du tilbakestille endringene?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Endringene lagres ikke"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Flere bakgrunner"</string> </resources> diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml index ced01b65..d74c088e 100644 --- a/res/values-ne/strings.xml +++ b/res/values-ne/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"जानकारी"</string> <string name="tab_customize" msgid="2533745409174959960">"आफू अनुकूल पार्नुहोस्"</string> <string name="tab_effects" msgid="3213606157589233901">"इफेक्टहरू"</string> + <string name="tab_share" msgid="6676269624804601227">"सेयर गर्नुहोस्"</string> <string name="my_photos" msgid="8613021349284084982">"मेरा फोटोहरू"</string> <string name="configure_wallpaper" msgid="849882179182976621">"सेटिङ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"मेट्नुहोस्"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"तपाईंको फोनबाट यो वालपेपर मेटाउने हो?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"परिवर्तन गर्नुहोस्"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"आफ्नो डिभाइसबाट यो वालपेपर मेटाउने हो?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"पछाडि फर्कनुहोस्"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"सम्पादन गर्नुहोस्"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"डाउनलोड गर्नुहोस्"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"स्क्रिन लक गर्नुहोस्"</string> <string name="home_screen_tab" msgid="1080445697837877526">"होम स्क्रिन"</string> <string name="reset" msgid="4945445169532850631">"रिसेट गर्नुहोस्"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"तपाईंले यसो गर्न खोज्नुभएकै हो?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"तपाईंले यसो गर्नुभयो भने तपाईंले परिवर्तन गरेका सबै कुरा रिसेट हुने छन्।"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"परिवर्तनहरू रिसेट गर्ने हो?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"तपाईंले गरेका परिवर्तनहरू सेभ गरिने छैनन्"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"थप वालपेपरहरू"</string> </resources> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index bec12053..33c1fc44 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informatie"</string> <string name="tab_customize" msgid="2533745409174959960">"Aanpassen"</string> <string name="tab_effects" msgid="3213606157589233901">"Effecten"</string> + <string name="tab_share" msgid="6676269624804601227">"Delen"</string> <string name="my_photos" msgid="8613021349284084982">"Mijn foto\'s"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Instellingen…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Verwijderen"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Wil je deze achtergrond verwijderen van je telefoon?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Bewerken"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Deze achtergrond verwijderen van je apparaat?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Terug"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Bewerken"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Downloaden"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Vergrendelscherm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Startscherm"</string> <string name="reset" msgid="4945445169532850631">"Resetten"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Weet je het zeker?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Hiermee worden al je wijzigingen gereset."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Wijzigingen resetten?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Je wijzigingen worden niet opgeslagen"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Meer achtergronden"</string> </resources> diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index ba538b9b..fbb01343 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -54,7 +54,7 @@ <string name="next_wallpaper" msgid="3911873152952596232">"ପରବର୍ତ୍ତୀ ୱାଲପେପର୍"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"ଏହି ଡିଭାଇସ୍ରେ ୱାଲପେପର୍ର ସେଟିଙ୍ଗକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string> <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"ୱାଲପେପର୍ର ସେଟିଙ୍ଗକୁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଆଡମିନିଷ୍ଟ୍ରେଟର୍ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> - <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"ୱାଲପେପର୍ ସଫଳତାର ସହ ସେଟ୍ ହୋଇଛି"</string> + <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"ୱାଲପେପର ସଫଳତାର ସହ ସେଟ ହୋଇଛି"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"ୱାଲପେପର୍ ଦେଖିବା ପାଇଁ ଗୋଟିଏ ଇଣ୍ଟର୍ନେଟ୍ କନେକ୍ସନ୍ ଆବଶ୍ୟକ। ଦୟାକରି କନେକ୍ଟ କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"ବର୍ତ୍ତମାନ ହୋମ ସ୍କ୍ରିନରେ ଥିବା ୱାଲପେପର୍ର ଥମ୍ବନେଲ୍କୁ ସେଟ କରନ୍ତୁ"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"ବର୍ତ୍ତମାନ ଲକ୍ ସ୍କ୍ରୀନ୍ରେ ଥିବା ୱାଲପେପର୍ର ଥମ୍ବନେଲ୍କୁ ଲକ୍ କରନ୍ତୁ"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ସୂଚନା"</string> <string name="tab_customize" msgid="2533745409174959960">"କଷ୍ଟମାଇଜ୍ କରନ୍ତୁ"</string> <string name="tab_effects" msgid="3213606157589233901">"ଇଫେକ୍ଟଗୁଡ଼ିକ"</string> + <string name="tab_share" msgid="6676269624804601227">"ସେୟାର କରନ୍ତୁ"</string> <string name="my_photos" msgid="8613021349284084982">"ମୋ ଫଟୋଗୁଡ଼ିକ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ସେଟିଂସ୍..."</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ଡିଲିଟ୍ କରନ୍ତୁ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ଆପଣଙ୍କର ଫୋନ୍ରୁ ଏହି ୱାଲ୍ପେପର୍କୁ ଡିଲିଟ୍ କରିବେ କି?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ଏଡିଟ କରନ୍ତୁ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ଆପଣଙ୍କ ଡିଭାଇସରୁ ଏହି ୱାଲପେପରକୁ ଡିଲିଟ କରିବେ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ପଛକୁ ଫେରନ୍ତୁ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ଏଡିଟ କରନ୍ତୁ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ଡାଉନଲୋଡ୍ କରନ୍ତୁ"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ଲକ ସ୍କ୍ରିନ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ହୋମ ସ୍କ୍ରିନ"</string> <string name="reset" msgid="4945445169532850631">"ରିସେଟ କରନ୍ତୁ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ଆପଣ ନିଶ୍ଚିତ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ଏହା ଆପଣ କରିଥିବା ସମସ୍ତ ପରିବର୍ତ୍ତନକୁ ରିସେଟ କରିବ।"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ପରିବର୍ତ୍ତନଗୁଡ଼ିକୁ ରିସେଟ କରିବେ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ଆପଣଙ୍କର ପରିବର୍ତ୍ତନଗୁଡ଼ିକୁ ସେଭ କରାଯିବ ନାହିଁ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ଅଧିକ ୱାଲପେପର"</string> </resources> diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml index 03c1ff71..73b3c8da 100644 --- a/res/values-pa/strings.xml +++ b/res/values-pa/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ਜਾਣਕਾਰੀ"</string> <string name="tab_customize" msgid="2533745409174959960">"ਵਿਉਂਤਬੱਧ ਕਰੋ"</string> <string name="tab_effects" msgid="3213606157589233901">"ਪ੍ਰਭਾਵ"</string> + <string name="tab_share" msgid="6676269624804601227">"ਸਾਂਝਾ ਕਰੋ"</string> <string name="my_photos" msgid="8613021349284084982">"ਮੇਰੀਆਂ ਫ਼ੋਟੋਆਂ"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ਸੈਟਿੰਗਾਂ…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ਮਿਟਾਓ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ਕੀ ਇਹ ਵਾਲਪੇਪਰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਮਿਟਾਉਣਾ ਹੈ?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ਸੰਪਾਦਨ ਕਰੋ"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ਕੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੋਂ ਇਸ ਵਾਲਪੇਪਰ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ਪਿੱਛੇ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ਸੰਪਾਦਨ ਕਰੋ"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ਡਾਊਨਲੋਡ ਕਰੋ"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ਲਾਕ ਸਕ੍ਰੀਨ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ਹੋਮ ਸਕ੍ਰੀਨ"</string> <string name="reset" msgid="4945445169532850631">"ਰੀਸੈੱਟ ਕਰੋ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ਪੱਕਾ?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਵੱਲੋਂ ਕੀਤੀਆਂ ਸਾਰੀਆਂ ਤਬਦੀਲੀਆਂ ਰੀਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ।"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"ਕੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ਤੁਹਾਡੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"ਹੋਰ ਵਾਲਪੇਪਰ"</string> </resources> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index c4e6f662..427d32e9 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacje"</string> <string name="tab_customize" msgid="2533745409174959960">"Dostosuj"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekty"</string> + <string name="tab_share" msgid="6676269624804601227">"Udostępnij"</string> <string name="my_photos" msgid="8613021349284084982">"Moje zdjęcia"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ustawienia…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Usuń"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Usunąć tę tapetę z telefonu?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Edytuj"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Usunąć tę tapetę z urządzenia?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Wstecz"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Edytuj"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Pobierz"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ekran blokady"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Ekran główny"</string> <string name="reset" msgid="4945445169532850631">"Resetuj"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Czy na pewno tego chcesz?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Spowoduje to cofnięcie wszystkich wprowadzonych zmian."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Zresetować zmiany?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Zmiany nie zostaną zapisane"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Więcej tapet"</string> </resources> diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 75fa890e..dd227abe 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -54,7 +54,7 @@ <string name="next_wallpaper" msgid="3911873152952596232">"Imagem de fundo seguinte"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"A definição de uma imagem de fundo está desativada neste dispositivo."</string> <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"A definição da imagem de fundo foi desativada pelo administrador do dispositivo."</string> - <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"Imagem de fundo definida com êxito."</string> + <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"Imagem de fundo definida com êxito"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"Precisa de uma ligação à Internet para ver imagens de fundo. Estabeleça ligação e tente novamente."</string> <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"Miniatura da imagem de fundo do ecrã principal definida atualmente"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"Miniatura da imagem de fundo do ecrã de bloqueio definida atualmente"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informações"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizar"</string> <string name="tab_effects" msgid="3213606157589233901">"Efeitos"</string> + <string name="tab_share" msgid="6676269624804601227">"Partilhe"</string> <string name="my_photos" msgid="8613021349284084982">"As minhas fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Definições…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Eliminar"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Eliminar esta imagem de fundo do telemóvel?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editar"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Apagar esta imagem de fundo do dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Anterior"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editar"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Transferir"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ecrã de bloqueio"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Ecrã principal"</string> <string name="reset" msgid="4945445169532850631">"Repor"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Tem a certeza?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Esta ação repõe todas as alterações que fez."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Repor alterações?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"As suas alterações não vão ser guardadas"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Mais imagens de fundo"</string> </resources> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index b02248e5..a9ac3372 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informações"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizar"</string> <string name="tab_effects" msgid="3213606157589233901">"Efeitos"</string> + <string name="tab_share" msgid="6676269624804601227">"Compartilhar"</string> <string name="my_photos" msgid="8613021349284084982">"Minhas fotos"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Configurações…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Excluir"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Excluir esse plano de fundo do seu smartphone?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editar"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Excluir esse plano de fundo do dispositivo?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Voltar"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editar"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Fazer o download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Tela de bloqueio"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Tela inicial"</string> <string name="reset" msgid="4945445169532850631">"Redefinir"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Tem certeza?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Essa ação redefine todas as mudanças feitas."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Redefinir mudanças?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"As mudanças não vão ser salvas"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Mais planos de fundo"</string> </resources> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 61d6b06c..088ce315 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informații"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizează"</string> <string name="tab_effects" msgid="3213606157589233901">"Efecte"</string> + <string name="tab_share" msgid="6676269624804601227">"Trimite"</string> <string name="my_photos" msgid="8613021349284084982">"Fotografiile mele"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Setări…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Șterge"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Ștergi această imagine de fundal de pe telefon?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Editează"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Ștergi imaginea de fundal de pe dispozitiv?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Înapoi"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Editează"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Descarcă"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ecran de blocare"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Ecran de pornire"</string> <string name="reset" msgid="4945445169532850631">"Resetează"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Confirmi?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Astfel, toate modificările pe care le-ai făcut vor fi resetate."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Resetezi modificările?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Modificările nu se vor salva"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Mai multe imagini de fundal"</string> </resources> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 010fa89a..4a65f09e 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Информация"</string> <string name="tab_customize" msgid="2533745409174959960">"Настройка"</string> <string name="tab_effects" msgid="3213606157589233901">"Эффекты"</string> + <string name="tab_share" msgid="6676269624804601227">"Поделиться"</string> <string name="my_photos" msgid="8613021349284084982">"Мои фото"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Настройки…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Удалить"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Удалить эти обои с телефона?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Изменить"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Удалить эти обои с устройства?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Изменить"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Скачать"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Заблокированный экран"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Главный экран"</string> <string name="reset" msgid="4945445169532850631">"Сбросить"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Вы уверены?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Все внесенные изменения будут сброшены."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Сбросить изменения?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Изменения не будут сохранены."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Ещё обои"</string> </resources> diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml index 923df35e..7da8afbf 100644 --- a/res/values-si/strings.xml +++ b/res/values-si/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"තතු"</string> <string name="tab_customize" msgid="2533745409174959960">"අභිරුචිකරණය කරන්න"</string> <string name="tab_effects" msgid="3213606157589233901">"ප්රයෝග"</string> + <string name="tab_share" msgid="6676269624804601227">"බෙදා ගන්න"</string> <string name="my_photos" msgid="8613021349284084982">"මගේ ඡායාරූප"</string> <string name="configure_wallpaper" msgid="849882179182976621">"සැකසීම්…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"මකන්න"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"මෙම බිතුපත ඔබේ දුරකථනයෙන් මකන්නද?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"සංස්කරණය කරන්න"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ඔබේ උපාංගයෙන් මෙම බිතුපත මකන්න ද?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"ආපසු යන්න"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"සංස්කරණය කරන්න"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"බාගන්න"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"අගුළු තිරය"</string> <string name="home_screen_tab" msgid="1080445697837877526">"මුල් තිරය"</string> <string name="reset" msgid="4945445169532850631">"යළි සකසන්න"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"ඔබට විශ්වාස ද?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"මෙය ඔබ සිදු කළ සියලු වෙනස්කම් යළි සකසනු ඇත."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"වෙනස්කම් යළි සකසන්න ද?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ඔබේ වෙනස්කම් සුරැකෙන්නේ නැත"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"තවත් වෝල්පේපර"</string> </resources> diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 264e7726..5ebc664d 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -77,14 +77,16 @@ <string name="center_wallpaper_position" msgid="4166894762352288883">"Vycentrovať"</string> <string name="center_crop_wallpaper_position" msgid="1681980019815343348">"Vycentrovať a orezať"</string> <string name="stretch_wallpaper_position" msgid="5002680983147456935">"Roztiahnuť"</string> - <string name="preview" msgid="1774602101743861071">"Zobraziť ukážku"</string> + <string name="preview" msgid="1774602101743861071">"Ukážka"</string> <string name="tab_info" msgid="818614080690111416">"Informácie"</string> <string name="tab_customize" msgid="2533745409174959960">"Prispôsobenie"</string> <string name="tab_effects" msgid="3213606157589233901">"Efekty"</string> + <string name="tab_share" msgid="6676269624804601227">"Zdieľanie"</string> <string name="my_photos" msgid="8613021349284084982">"Moje fotky"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Nastavenia…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Odstrániť"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Chcete túto tapetu odstrániť z telefónu?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Upraviť"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Chcete zo zariadenia odstrániť túto tapetu?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Späť"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Upraviť"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Stiahnuť"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Uzamknutá obrazovka"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Plocha"</string> <string name="reset" msgid="4945445169532850631">"Resetovať"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Naozaj to chcete urobiť?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Týmto resetujete všetky vykonané zmeny."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Chcete resetovať zmeny?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Vaše zmeny nebudú uložené"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Ďalšie tapety"</string> </resources> diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 516fd2b8..ededc702 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -54,7 +54,7 @@ <string name="next_wallpaper" msgid="3911873152952596232">"Naslednje ozadje"</string> <string name="wallpaper_disabled_message" msgid="7309484130562148185">"Nastavljanje ozadja je v tej napravi onemogočeno"</string> <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"Nastavljanje ozadja je onemogočil skrbnik naprave"</string> - <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"Ozadje uspešno nastavljeno"</string> + <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"Ozadje je uspešno nastavljeno"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"Če si želite ogledati ozadja, potrebujete internetno povezavo. Vzpostavite povezavo in poskusite znova."</string> <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"Sličica trenutno nastavljenega ozadja za začetni zaslon"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"Sličica trenutno nastavljenega ozadja za zaklenjen zaslon"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacije"</string> <string name="tab_customize" msgid="2533745409174959960">"Prilagajanje"</string> <string name="tab_effects" msgid="3213606157589233901">"Učinki"</string> + <string name="tab_share" msgid="6676269624804601227">"Deli"</string> <string name="my_photos" msgid="8613021349284084982">"Moje fotografije"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Nastavitve …"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Izbriši"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Ali želite to ozadje izbrisati iz telefona?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Uredi"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Ali želite to zaslonsko ozadje izbrisati iz naprave?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Nazaj"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Urejanje"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Prenos"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Zaklenjen zaslon"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Začetni zaslon"</string> <string name="reset" msgid="4945445169532850631">"Ponastavi"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ali ste prepričani?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"S tem boste ponastavili vse izvedene spremembe."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Želite ponastaviti spremembe?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Spremembe ne bodo shranjene."</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Več zaslonskih ozadij"</string> </resources> diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 78424cb9..e72d7fb5 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Informacione"</string> <string name="tab_customize" msgid="2533745409174959960">"Personalizo"</string> <string name="tab_effects" msgid="3213606157589233901">"Efektet"</string> + <string name="tab_share" msgid="6676269624804601227">"Ndaj"</string> <string name="my_photos" msgid="8613021349284084982">"Fotografitë e mia"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Cilësimet…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Fshi"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Do ta fshish këtë imazh sfondi nga telefoni?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Modifiko"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Të fshihet ky imazh sfondi nga pajisja jote?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Pas"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Modifiko"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Shkarko"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ekrani i kyçjes"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Ekrani bazë"</string> <string name="reset" msgid="4945445169532850631">"Rivendos"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"E konfirmon?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Kjo do t\'i rivendosë të gjitha ndryshimet që bëre."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Të rivendosen ndryshimet?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Ndryshimet e tua nuk do të ruhen"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Më shumë imazhe të sfondit"</string> </resources> diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index c894c797..ee7b7b3d 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Информације"</string> <string name="tab_customize" msgid="2533745409174959960">"Прилагодите"</string> <string name="tab_effects" msgid="3213606157589233901">"Ефекти"</string> + <string name="tab_share" msgid="6676269624804601227">"Делите"</string> <string name="my_photos" msgid="8613021349284084982">"Моје слике"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Подешавања…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Избриши"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Желите да избришете ову позадину са телефона?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Измени"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Желите да избришете ову позадину са уређаја?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Измени"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Преузми"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Закључани екран"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Почетни екран"</string> <string name="reset" msgid="4945445169532850631">"Ресетуј"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Јесте ли сигурни?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Овим ресетујете све промене које сте унели."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Желите да ресетујете промене?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Промене неће бити сачуване"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Још позадина"</string> </resources> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 6b6403e9..e66e377c 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Information"</string> <string name="tab_customize" msgid="2533745409174959960">"Anpassa"</string> <string name="tab_effects" msgid="3213606157589233901">"Effekter"</string> + <string name="tab_share" msgid="6676269624804601227">"Dela"</string> <string name="my_photos" msgid="8613021349284084982">"Mina bilder"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Inställningar…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Radera"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Vill du radera den här bakgrunden från mobilen?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Redigera"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Vill du radera den här bakgrunden från enheten?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Tillbaka"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Redigera"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Ladda ned"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Låsskärm"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Startskärm"</string> <string name="reset" msgid="4945445169532850631">"Återställ"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Är du säker?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Detta återställer alla dina ändringar."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Vill du återställa ändringarna?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Dina ändringar sparas inte"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Fler bakgrunder"</string> </resources> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index d6be66c7..1c2984ec 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Maelezo"</string> <string name="tab_customize" msgid="2533745409174959960">"Weka mapendeleo"</string> <string name="tab_effects" msgid="3213606157589233901">"Madoido"</string> + <string name="tab_share" msgid="6676269624804601227">"Shiriki"</string> <string name="my_photos" msgid="8613021349284084982">"Picha Zangu"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Mipangilio…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Futa"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Je, ungependa kufuta mandhari haya kwenye simu yako?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Badilisha"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Ungependa kufuta mandhari haya kwenye kifaa chako?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Nyuma"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Badilisha"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Pakua"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Skrini iliyofungwa"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Skrini ya kwanza"</string> <string name="reset" msgid="4945445169532850631">"Weka upya"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Una uhakika?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Hali hii itaweka upya mabadiliko yote uliyofanya."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Ungependa kuweka mabadiliko upya?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Mabadiliko yako hayatahifadhiwa"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Mandhari Zaidi"</string> </resources> diff --git a/res/values-sw480dp/bools.xml b/res/values-sw480dp/bools.xml new file mode 100644 index 00000000..1c2e03bb --- /dev/null +++ b/res/values-sw480dp/bools.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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. +--> +<resources> + <bool name="is_large_screen">false</bool> +</resources>
\ No newline at end of file diff --git a/res/values-sw550dp/bools.xml b/res/values-sw550dp/bools.xml new file mode 100644 index 00000000..11971671 --- /dev/null +++ b/res/values-sw550dp/bools.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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. +--> +<resources> + <bool name="is_large_screen">true</bool> +</resources>
\ No newline at end of file diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 199e320d..5aaa3792 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"தகவல்"</string> <string name="tab_customize" msgid="2533745409174959960">"பிரத்தியேகமாக்கு"</string> <string name="tab_effects" msgid="3213606157589233901">"எஃபெக்ட்டுகள்"</string> + <string name="tab_share" msgid="6676269624804601227">"பகிர்"</string> <string name="my_photos" msgid="8613021349284084982">"எனது புகைப்படங்கள்"</string> <string name="configure_wallpaper" msgid="849882179182976621">"அமைப்புகள்…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"நீக்கு"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"மொபைலில் இருந்து இந்த வால்பேப்பரை நீக்கவா?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"மாற்று"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"உங்கள் சாதனத்திலிருந்து இந்த வால்பேப்பரை நீக்கவா?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"பின்செல்வதற்கான பட்டன்"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"திருத்துவதற்கான பட்டன்"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"பதிவிறக்குவதற்கான பட்டன்"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"பூட்டுத் திரை"</string> <string name="home_screen_tab" msgid="1080445697837877526">"முகப்புத் திரை"</string> <string name="reset" msgid="4945445169532850631">"மீட்டமை"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"நிச்சயமாக மீட்டமைக்க வேண்டுமா?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"இது நீங்கள் செய்த அனைத்து மாற்றங்களையும் மீட்டமைக்கும்."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"மாற்றங்களை மீட்டமைக்கவா?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"உங்கள் மாற்றங்கள் சேமிக்கப்படாது"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"கூடுதல் வால்பேப்பர்கள்"</string> </resources> diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index 7fdb8c3d..8c8f71c5 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -21,7 +21,7 @@ <!-- no translation found for app_name (8773648973927541493) --> <skip /> <string name="select_wallpaper_label" msgid="6989581259339646085">"వాల్పేపర్ రకాలు"</string> - <string name="set_wallpaper_button_text" msgid="4426286890442731310">"వాల్పేపర్ను సెట్ చేయి"</string> + <string name="set_wallpaper_button_text" msgid="4426286890442731310">"వాల్పేపర్ను సెట్ చేయండి"</string> <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"వాల్పేపర్ను సెట్ చేస్తోంది…"</string> <string name="try_again" msgid="8278874823700921234">"మళ్లీ ప్రయత్నించు"</string> <string name="set_wallpaper_error_message" msgid="6819986999041085130">"వాల్పేపర్ను సెట్ చేయడం సాధ్యపడలేదు."</string> @@ -37,8 +37,8 @@ <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"లాక్ స్క్రీన్"</string> <string name="set_wallpaper_both_destination" msgid="2536004558738350775">"మొదటి ట్యాబ్, లాక్ స్క్రీన్"</string> <string name="no_backup_image_wallpaper_label" msgid="6316627676107284851">"చిత్ర వాల్పేపర్ను వంతుల వారీగా మార్చడం"</string> - <string name="permission_needed_explanation" msgid="139166837541426823">"ప్రస్తుత వాల్పేపర్ని ఇక్కడ ప్రదర్శించడానికి, <xliff:g id="APP_NAME">%1$s</xliff:g>కి మీ పరికర నిల్వ యొక్క యాక్సెస్ అవసరమవుతుంది."</string> - <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"ఇక్కడ ప్రస్తుత వాల్పేపర్ను ప్రదర్శించడానికి, వాల్పేపర్లకు మీ పరికర నిల్వ యాక్సెస్ అవసరం.\n\nఈ సెట్టింగ్ను మార్చడానికి, వాల్పేపర్ల యాప్ సమాచారం యొక్క అనుమతుల ప్రాంతానికి వెళ్లండి."</string> + <string name="permission_needed_explanation" msgid="139166837541426823">"ప్రస్తుత వాల్పేపర్ని ఇక్కడ ప్రదర్శించడానికి, <xliff:g id="APP_NAME">%1$s</xliff:g>కి మీ పరికర స్టోరేజ్ యొక్క యాక్సెస్ అవసరమవుతుంది."</string> + <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"ఇక్కడ ప్రస్తుత వాల్పేపర్ను ప్రదర్శించడానికి, వాల్పేపర్లకు మీ పరికర స్టోరేజ్ యాక్సెస్ అవసరం.\n\nఈ సెట్టింగ్ను మార్చడానికి, వాల్పేపర్ల యాప్ సమాచారం యొక్క అనుమతుల ప్రాంతానికి వెళ్లండి."</string> <string name="permission_needed_allow_access_button_label" msgid="1943133660612924306">"యాక్సెస్ని ఇవ్వండి"</string> <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"వాల్పేపర్లను వంతుల వారీగా మార్చడం లైవ్ వాల్పేపర్ సేవ"</string> <string name="daily_refresh_tile_title" msgid="3270456074558525091">"రోజువారీ వాల్పేపర్"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"సమాచారం"</string> <string name="tab_customize" msgid="2533745409174959960">"అనుకూలంగా మార్చండి"</string> <string name="tab_effects" msgid="3213606157589233901">"ఎఫెక్ట్లు"</string> + <string name="tab_share" msgid="6676269624804601227">"షేర్ చేయండి"</string> <string name="my_photos" msgid="8613021349284084982">"నా ఫోటోలు"</string> <string name="configure_wallpaper" msgid="849882179182976621">"సెట్టింగ్లు…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"తొలగించండి"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"మీ ఫోన్ నుండి ఈ వాల్పేపర్ను తొలగించాలా?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ఎడిట్ చేయండి"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"మీ పరికరం నుండి ఈ వాల్పేపర్ను తొలగించాలా?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"వెనుకకు"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ఎడిట్"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"డౌన్లోడ్"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"లాక్ స్క్రీన్"</string> <string name="home_screen_tab" msgid="1080445697837877526">"మొదటి స్క్రీన్"</string> <string name="reset" msgid="4945445169532850631">"రీసెట్ చేయి"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"మీరు రీసెట్ చేయాలనుకుంటున్నారా?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"ఇది మీరు చేసిన అన్ని మార్పులను రీసెట్ చేస్తుంది."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"మార్పులను రీసెట్ చేయాలా?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"మీ మార్పులు సేవ్ చేయబడవు"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"మరిన్ని వాల్పేపర్లు"</string> </resources> diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index b7badedd..5b880051 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"ข้อมูล"</string> <string name="tab_customize" msgid="2533745409174959960">"ปรับแต่ง"</string> <string name="tab_effects" msgid="3213606157589233901">"เอฟเฟกต์"</string> + <string name="tab_share" msgid="6676269624804601227">"แชร์"</string> <string name="my_photos" msgid="8613021349284084982">"รูปภาพของฉัน"</string> <string name="configure_wallpaper" msgid="849882179182976621">"การตั้งค่า…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"ลบ"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"ลบวอลเปเปอร์นี้ออกจากโทรศัพท์ไหม"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"แก้ไข"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"ลบวอลเปเปอร์นี้ออกจากอุปกรณ์ไหม"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"กลับ"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"แก้ไข"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ดาวน์โหลด"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"ล็อกหน้าจอ"</string> <string name="home_screen_tab" msgid="1080445697837877526">"หน้าจอหลัก"</string> <string name="reset" msgid="4945445169532850631">"รีเซ็ต"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"คุณแน่ใจใช่ไหม"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"การดำเนินการนี้จะรีเซ็ตการเปลี่ยนแปลงทั้งหมดที่คุณทำ"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"รีเซ็ตการเปลี่ยนแปลงไหม"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"ระบบจะไม่บันทึกการเปลี่ยนแปลงของคุณ"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"วอลเปเปอร์เพิ่มเติม"</string> </resources> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index b45da502..a26eb4e2 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Impormasyon"</string> <string name="tab_customize" msgid="2533745409174959960">"I-customize"</string> <string name="tab_effects" msgid="3213606157589233901">"Mga Effect"</string> + <string name="tab_share" msgid="6676269624804601227">"I-share"</string> <string name="my_photos" msgid="8613021349284084982">"Mga Larawan Ko"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Mga Setting…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"I-delete"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"I-delete ang wallpaper na ito sa iyong telepono?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"I-edit"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"I-delete ang wallpaper na ito mula sa iyong device?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Bumalik"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"I-edit"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"I-download"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"I-lock ang screen"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Home screen"</string> <string name="reset" msgid="4945445169532850631">"I-reset"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Sigurado ka ba?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Ire-reset nito ang lahat ng pagbabagong ginawa mo."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"I-reset ang mga pagbabago?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Hindi mase-save ang iyong mga pagbabago"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Higit Pang Wallpaper"</string> </resources> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index f4fc63e6..f1bde84d 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Bilgi"</string> <string name="tab_customize" msgid="2533745409174959960">"Özelleştir"</string> <string name="tab_effects" msgid="3213606157589233901">"Efektler"</string> + <string name="tab_share" msgid="6676269624804601227">"Paylaş"</string> <string name="my_photos" msgid="8613021349284084982">"Fotoğraflarım"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Ayarlar…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Sil"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Bu duvar kağıdı telefonunuzdan silinsin mi?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Düzenle"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Bu duvar kağıdı cihazınızdan silinsin mi?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Geri"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Düzenle"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"İndir"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Kilit ekranı"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Ana ekran"</string> <string name="reset" msgid="4945445169532850631">"Sıfırla"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Emin misiniz?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Bu işlemle, yaptığınız tüm değişiklikler sıfırlanacak."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Değişiklikler sıfırlansın mı?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Değişiklikleriniz kaydedilmeyecek"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Diğer Duvar Kağıtları"</string> </resources> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index f8f148c2..67a4f366 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Інформація"</string> <string name="tab_customize" msgid="2533745409174959960">"Налаштування"</string> <string name="tab_effects" msgid="3213606157589233901">"Ефекти"</string> + <string name="tab_share" msgid="6676269624804601227">"Поділіться"</string> <string name="my_photos" msgid="8613021349284084982">"Мої фото"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Налаштування…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Видалити"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Видалити цей фоновий малюнок із телефона?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Редагувати"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Видалити цей фоновий малюнок із пристрою?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Назад"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Змінити"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Завантажити"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Заблокований екран"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Головний екран"</string> <string name="reset" msgid="4945445169532850631">"Скинути"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Продовжити?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Усі внесені зміни буде скасовано."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Скинути зміни?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Зміни не буде збережено"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Більше фонових малюнків"</string> </resources> diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index 8f212f7d..94320bdf 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"معلومات"</string> <string name="tab_customize" msgid="2533745409174959960">"حسب ضرورت بنائیں"</string> <string name="tab_effects" msgid="3213606157589233901">"اثرات"</string> + <string name="tab_share" msgid="6676269624804601227">"اشتراک کریں"</string> <string name="my_photos" msgid="8613021349284084982">"میری تصاویر"</string> <string name="configure_wallpaper" msgid="849882179182976621">"ترتیبات…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"حذف کریں"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"اس وال پیپر کو آپ کے فون سے حذف کریں؟"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"ترمیم کریں"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"اپنے آلے سے اس وال پیپر کو حذف کریں؟"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"واپس جائیں"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"ترمیم کریں"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"ڈاؤن لوڈ کریں"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"مقفل اسکرین"</string> <string name="home_screen_tab" msgid="1080445697837877526">"ہوم اسکرین"</string> <string name="reset" msgid="4945445169532850631">"ری سیٹ کریں"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"آپ پُر یقین ہیں؟"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"یہ آپ کی کی گئی تمام تبدیلیوں کو ری سیٹ کر دے گا۔"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"تبدیلیوں کو ری سیٹ کریں؟"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"آپ کی تبدیلیاں محفوظ نہیں ہوں گی"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"مزید وال پیپرز"</string> </resources> diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 701b5c7f..6b419fc5 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Axborot"</string> <string name="tab_customize" msgid="2533745409174959960">"Sozlash"</string> <string name="tab_effects" msgid="3213606157589233901">"Effektlar"</string> + <string name="tab_share" msgid="6676269624804601227">"Ulashish"</string> <string name="my_photos" msgid="8613021349284084982">"Mening suratlarim"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Sozlamalar…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Oʻchirish"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Bu fon rasmi telefoningizdan oʻchirib tashlansinmi?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Tahrirlash"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Bu fon rasmi qurilmangizdan oʻchirib tashlansinmi?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Orqaga"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Tahrirlash"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Yuklab olish"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Ekran qulfi"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Bosh ekran"</string> <string name="reset" msgid="4945445169532850631">"Yangilash"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Ishonchingiz komilmi?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Barcha oʻzgarishlarni asliga tiklaydi."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Oʻzgarishlar asliga qaytarilsinmi?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Oʻzgarishlar saqlanmaydi"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Boshqa fon rasmlari"</string> </resources> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 4899bbf2..5fff4972 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Thông tin"</string> <string name="tab_customize" msgid="2533745409174959960">"Tùy chỉnh"</string> <string name="tab_effects" msgid="3213606157589233901">"Hiệu ứng"</string> + <string name="tab_share" msgid="6676269624804601227">"Chia sẻ"</string> <string name="my_photos" msgid="8613021349284084982">"Ảnh của tôi"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Cài đặt…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Xóa"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Bạn muốn xóa hình nền này khỏi điện thoại của mình?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Chỉnh sửa"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Xoá hình nền này khỏi thiết bị của bạn?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Quay lại"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Chỉnh sửa"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Tải xuống"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Màn hình khoá"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Màn hình chính"</string> <string name="reset" msgid="4945445169532850631">"Đặt lại"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Bạn có chắc chắn không?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Thao tác này sẽ đặt lại tất cả thay đổi bạn đã thực hiện."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Đặt lại nội dung thay đổi?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Thay đổi của bạn sẽ không được lưu"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Hình nền khác"</string> </resources> diff --git a/res/values-w600dp-port/dimens.xml b/res/values-w600dp-port/dimens.xml index 947dfe82..07d8b0f9 100644 --- a/res/values-w600dp-port/dimens.xml +++ b/res/values-w600dp-port/dimens.xml @@ -47,4 +47,8 @@ <!-- Dimensions for GridFragment. --> <dimen name="grid_options_container_horizontal_margin">64dp</dimen> + + <!-- Clipping of the home screen overlay --> + <dimen name="home_screen_overlay_top_clipping">0dp</dimen> + <dimen name="home_screen_overlay_bottom_clipping">100dp</dimen> </resources>
\ No newline at end of file diff --git a/res/values-w800dp/dimens.xml b/res/values-w800dp/dimens.xml index 54d90024..23217870 100644 --- a/res/values-w800dp/dimens.xml +++ b/res/values-w800dp/dimens.xml @@ -59,4 +59,8 @@ <dimen name="preview_page_top_margin">96dp</dimen> <dimen name="preview_page_bottom_margin">72dp</dimen> <dimen name="grid_options_container_horizontal_margin">152dp</dimen> + + <!-- Clipping of the home screen overlay --> + <dimen name="home_screen_overlay_top_clipping">0dp</dimen> + <dimen name="home_screen_overlay_bottom_clipping">80dp</dimen> </resources>
\ No newline at end of file diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 79ae629f..fd3c7c71 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"信息"</string> <string name="tab_customize" msgid="2533745409174959960">"自定义"</string> <string name="tab_effects" msgid="3213606157589233901">"效果"</string> + <string name="tab_share" msgid="6676269624804601227">"分享"</string> <string name="my_photos" msgid="8613021349284084982">"我的照片"</string> <string name="configure_wallpaper" msgid="849882179182976621">"设置…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"删除"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"要从您的手机上删除此壁纸吗?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"修改"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"要从您的设备中删除此壁纸吗?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"返回"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"修改"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"下载"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"锁定屏幕"</string> <string name="home_screen_tab" msgid="1080445697837877526">"主屏幕"</string> <string name="reset" msgid="4945445169532850631">"重置"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"确定吗?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"此操作将重置您做出的所有更改。"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"要重置更改吗?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"您所做的更改将不会保存"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"更多壁纸"</string> </resources> diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 41784898..8cc0e272 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"資訊"</string> <string name="tab_customize" msgid="2533745409174959960">"自訂"</string> <string name="tab_effects" msgid="3213606157589233901">"效果"</string> + <string name="tab_share" msgid="6676269624804601227">"分享"</string> <string name="my_photos" msgid="8613021349284084982">"我的相片"</string> <string name="configure_wallpaper" msgid="849882179182976621">"設定…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"刪除"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"要從手機中刪除此桌布嗎?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"編輯"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"要從您的裝置刪除此桌布嗎?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"返回"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"編輯"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"下載"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"上鎖畫面"</string> <string name="home_screen_tab" msgid="1080445697837877526">"主畫面"</string> <string name="reset" msgid="4945445169532850631">"重設"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"您確定嗎?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"此操作將重設您所作的所有變更。"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"要重設變更嗎?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"您的變更不會儲存"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"更多桌布"</string> </resources> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 3015dd90..b37d3344 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -28,10 +28,10 @@ <string name="load_wallpaper_error_message" msgid="7913278480467707374">"無法載入桌布。圖片已毀損或無法使用。"</string> <string name="static_wallpaper_presentation_mode_message" msgid="417940227049360906">"目前設定的桌布"</string> <string name="rotating_wallpaper_presentation_mode_message" msgid="3361676041605733288">"每日桌布"</string> - <string name="wallpaper_destination_both" msgid="1124197176741944063">"主螢幕和螢幕鎖定"</string> + <string name="wallpaper_destination_both" msgid="1124197176741944063">"主畫面和螢幕鎖定"</string> <string name="home_screen_message" msgid="106444102822522813">"主畫面"</string> <string name="lock_screen_message" msgid="1534506081955058013">"螢幕鎖定"</string> - <string name="home_and_lock_short_label" msgid="2937922943541927983">"主螢幕和螢幕鎖定"</string> + <string name="home_and_lock_short_label" msgid="2937922943541927983">"主畫面和螢幕鎖定"</string> <string name="set_wallpaper_dialog_message" msgid="2110475703996853076">"設定以下畫面的桌布:"</string> <string name="set_wallpaper_home_screen_destination" msgid="7315594722013109354">"主畫面"</string> <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"螢幕鎖定"</string> @@ -56,13 +56,13 @@ <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"你的裝置管理員已停用設定桌布的功能"</string> <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"已成功設定桌布"</string> <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"必須連上網際網路才能查看桌布。請連上網路,然後再試一次。"</string> - <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"目前設定的主螢幕桌布縮圖"</string> + <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"目前設定的主畫面桌布縮圖"</string> <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"目前設定的螢幕鎖定桌布縮圖"</string> <string name="currently_set_wallpaper_thumbnail" msgid="8651887838745545107">"目前設定的桌布縮圖"</string> <string name="wallpaper_thumbnail" msgid="569931475923605974">"桌布縮圖"</string> - <string name="explore_home_screen" msgid="8756346794535765482">"探索主螢幕桌布"</string> + <string name="explore_home_screen" msgid="8756346794535765482">"探索主畫面桌布"</string> <string name="explore_lock_screen" msgid="268938342103703665">"探索螢幕鎖定桌布"</string> - <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"重新整理主螢幕每日桌布"</string> + <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"重新整理主畫面每日桌布"</string> <string name="refresh_daily_wallpaper_content_description" msgid="4362142658237147583">"重新整理每日桌布"</string> <string name="refreshing_daily_wallpaper_dialog_message" msgid="1975910873362855761">"正在重新整理每日桌布…"</string> <string name="refresh_daily_wallpaper_failed_message" msgid="4749879993812557166">"無法重新整理每日桌布。請檢查你的網路連線,然後再試一次。"</string> @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"資訊"</string> <string name="tab_customize" msgid="2533745409174959960">"自訂"</string> <string name="tab_effects" msgid="3213606157589233901">"特效"</string> + <string name="tab_share" msgid="6676269624804601227">"分享"</string> <string name="my_photos" msgid="8613021349284084982">"我的相片"</string> <string name="configure_wallpaper" msgid="849882179182976621">"設定…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"刪除"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"要從手機中刪除這張桌布嗎?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"編輯"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"要將這張桌布從裝置中刪除嗎?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"返回"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"編輯"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"下載"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"螢幕鎖定畫面"</string> <string name="home_screen_tab" msgid="1080445697837877526">"主畫面"</string> <string name="reset" msgid="4945445169532850631">"重設"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"確定要這麼做嗎?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"這麼做會重設你進行的所有變更。"</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"要重設變更嗎?"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"系統不會儲存你的變更"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"更多桌布"</string> </resources> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 27554a49..98f55393 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -81,10 +81,12 @@ <string name="tab_info" msgid="818614080690111416">"Ulwazi"</string> <string name="tab_customize" msgid="2533745409174959960">"Enza ngendlela oyifisayo"</string> <string name="tab_effects" msgid="3213606157589233901">"Imiphumela"</string> + <string name="tab_share" msgid="6676269624804601227">"Yabelana"</string> <string name="my_photos" msgid="8613021349284084982">"Izithombe zami"</string> <string name="configure_wallpaper" msgid="849882179182976621">"Izilungiselelo…"</string> <string name="delete_live_wallpaper" msgid="589212696102662329">"Susa"</string> - <string name="delete_wallpaper_confirmation" msgid="33790318361863778">"Landa lesi sithombe esingemuva kusukela kufoni yakho?"</string> + <string name="edit_live_wallpaper" msgid="3132060073690558045">"Hlela"</string> + <string name="delete_wallpaper_confirmation" msgid="1905114562243802354">"Sula lesi sithombe sangemuva kudivayisi yakho?"</string> <string name="bottom_action_bar_back" msgid="8237013112999946725">"Emuva"</string> <string name="bottom_action_bar_edit" msgid="1214742990893082138">"Hlela"</string> <string name="bottom_action_bar_download" msgid="3983122338076389421">"Landa"</string> @@ -114,6 +116,7 @@ <string name="lock_screen_tab" msgid="6672930765010407652">"Khiya isikrini"</string> <string name="home_screen_tab" msgid="1080445697837877526">"Isikrini sasekhaya"</string> <string name="reset" msgid="4945445169532850631">"Setha kabusha"</string> - <string name="reset_confirmation_dialog_title" msgid="3006691785800178536">"Uqinisekile?"</string> - <string name="reset_confirmation_dialog_message" msgid="4304013650135221616">"Lokhu kuzosetha kabusha zonke izinhlobo ozenzile."</string> + <string name="reset_confirmation_dialog_title" msgid="3391905685838213712">"Setha kabusha izinguquko"</string> + <string name="reset_confirmation_dialog_message" msgid="888669268626289603">"Izinguquko zakho ngeke zilondolozwe"</string> + <string name="more_wallpapers" msgid="7585665124282737376">"Izithombe Zangemuva Ezengeziwe"</string> </resources> diff --git a/res/values/bools.xml b/res/values/bools.xml new file mode 100644 index 00000000..1c2e03bb --- /dev/null +++ b/res/values/bools.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 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. +--> +<resources> + <bool name="is_large_screen">false</bool> +</resources>
\ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index c6dc8ba7..ec437ad3 100755 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -51,6 +51,9 @@ <color name="color_surface">@color/settingslib_colorSurface</color> <color name="color_surface_variant">@color/settingslib_colorSurfaceVariant</color> <color name="text_color_primary">@color/settingslib_text_color_primary</color> + <color name="text_color_primary_inverse">@android:color/system_neutral1_900</color> <color name="text_color_secondary">@color/settingslib_text_color_secondary</color> <color name="text_color_secondary_inverse">@color/settingslib_text_color_secondary_device_default</color> + + <color name="wallpaper_preview_scrim_color">#99000000</color> </resources> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 7c27bd94..98332373 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -67,6 +67,7 @@ <!-- Dimensions for wallpaper tiles in individual picker when in desktop mode. --> <dimen name="tile_desktop_progress_bar_size">40dp</dimen> + <dimen name="effect_generating_progress_bar_size">48dp</dimen> <!-- Dimensions for "daily refresh" rotation tile in individual picker when in desktop mode. --> <dimen name="rotation_tile_desktop_label_padding">16dp</dimen> @@ -218,6 +219,7 @@ <dimen name="wallpaper_picker_entry_horizontal_padding">16dp</dimen> <dimen name="wallpaper_picker_entry_margin_vertical">16dp</dimen> <dimen name="wallpaper_picker_entry_card_corner_radius">12dp</dimen> + <dimen name="wallpaper_preview_buttons_elevation">8dp</dimen> <!-- For the full screen preview activity's hide UI menu item --> <dimen name="menu_item_hide_ui_background_width">46dp</dimen> @@ -239,7 +241,7 @@ <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_top_clipping">90dp</dimen> <dimen name="home_screen_overlay_bottom_clipping">40dp</dimen> <!-- Set wallpaper button --> @@ -261,7 +263,6 @@ <!-- Duo tabs --> <dimen name="duo_tabs_button_corner_radius">12dp</dimen> - <dimen name="duo_tabs_divider_space">8dp</dimen> <!-- Floating Sheet --> <dimen name="floating_sheet_corner_radius">12dp</dimen> @@ -276,4 +277,19 @@ display. --> <dimen name="screen_preview_height">380dp</dimen> + + <!-- Height of options in the wallpaper quick switch widget. --> + <dimen name="wallpaper_quick_switch_selected_option_height">98dp</dimen> + + <!-- Maximumn width non-selected options in the wallpaper quick switch widget. --> + <dimen name="wallpaper_quick_switch_max_option_width">@dimen/wallpaper_quick_switch_selected_option_height</dimen> + + <dimen name="spacing_8dp">8dp</dimen> + <dimen name="spacing_10dp">10dp</dimen> + + <!-- Horizontal padding around the "duo tabs" at the top of the screen. --> + <dimen name="tab_container_horizontal_padding">24dp</dimen> + + <!-- Size for option items. --> + <dimen name="option_item_size">74dp</dimen> </resources> diff --git a/res/values/ids.xml b/res/values/ids.xml new file mode 100644 index 00000000..8db206d7 --- /dev/null +++ b/res/values/ids.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 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. + ~ + --> + +<resources> + <item name="background" type="id" /> + <item name="foreground" type="id" /> + <item name="text" type="id" /> + <item name="selection_border" type="id" /> +</resources>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index e5b104fd..0f439c8a 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -303,6 +303,10 @@ [CHAR_LIMIT=25] --> <string name="tab_effects">Effects</string> + <!-- Label for the 'Share' tab of view pager in wallpaper preview activity. + [CHAR_LIMIT=25] --> + <string name="tab_share">Share</string> + <!-- Generic label for the my photos action [CHAR_LIMIT=20] --> <string name="my_photos">My Photos</string> @@ -312,8 +316,11 @@ <!-- List item for deleting the current wallpaper [CHAR LIMIT=30] --> <string name="delete_live_wallpaper">Delete</string> + <!-- List item for editing the current wallpaper [CHAR LIMIT=NONE] --> + <string name="edit_live_wallpaper">Edit</string> + <!-- Confirmation dialog. Shown after user selects to delete one wallpaper. [CHAR LIMIT=NONE] --> - <string name="delete_wallpaper_confirmation">Delete this wallpaper from your phone?</string> + <string name="delete_wallpaper_confirmation">Delete this wallpaper from your device?</string> <!-- Content description of back button on the bottom action bar. [CHAR LIMIT=30] --> <string name="bottom_action_bar_back">Back</string> @@ -435,7 +442,7 @@ [CHAR LIMIT=32]. --> - <string name="reset_confirmation_dialog_title">Are you sure?</string> + <string name="reset_confirmation_dialog_title">Reset changes?</string> <!-- Message for dialog confirming with the user that they really wish to reset the customizations @@ -443,5 +450,13 @@ [CHAR LIMIT=128]. --> - <string name="reset_confirmation_dialog_message">This will reset all changes you made.</string> + <string name="reset_confirmation_dialog_message">Your changes won\'t be saved</string> + + <!-- + Label for button that lets the user navigate to a full-screen experience of selecting + wallpapers. + + [CHAR LIMIT=128]. + --> + <string name="more_wallpapers">More Wallpapers</string> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index b48fba0e..ae7f3938 100755 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -218,4 +218,22 @@ <item name="android:textSize">36sp</item> <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item> </style> + + <style name="DialogButton"> + <item name="android:gravity">center</item> + <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Small</item> + <item name="android:textFontWeight">500</item> + <item name="android:paddingVertical">8dp</item> + <item name="android:paddingHorizontal">16dp</item> + </style> + + <style name="DialogButton.Primary"> + <item name="android:textColor">@color/text_color_on_accent</item> + <item name="android:background">@drawable/primary_dialog_button_background</item> + </style> + + <style name="DialogButton.Secondary"> + <item name="android:textColor">@color/text_color_primary</item> + <item name="android:background">@drawable/secondary_dialog_button_background</item> + </style> </resources> diff --git a/src/com/android/wallpaper/asset/LiveWallpaperThumbAsset.java b/src/com/android/wallpaper/asset/LiveWallpaperThumbAsset.java index 1f4fb674..08486a12 100755 --- a/src/com/android/wallpaper/asset/LiveWallpaperThumbAsset.java +++ b/src/com/android/wallpaper/asset/LiveWallpaperThumbAsset.java @@ -21,16 +21,23 @@ import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.net.Uri; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.widget.ImageView; import androidx.annotation.WorkerThread; +import com.android.wallpaper.module.DrawableLayerResolver; +import com.android.wallpaper.module.InjectorProvider; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.MultiTransformation; @@ -59,6 +66,7 @@ public class LiveWallpaperThumbAsset extends Asset { protected final Context mContext; protected final android.app.WallpaperInfo mInfo; + protected final DrawableLayerResolver mLayerResolver; // The content Uri of thumbnail protected Uri mUri; private Drawable mThumbnailDrawable; @@ -66,6 +74,7 @@ public class LiveWallpaperThumbAsset extends Asset { public LiveWallpaperThumbAsset(Context context, android.app.WallpaperInfo info) { mContext = context.getApplicationContext(); mInfo = info; + mLayerResolver = InjectorProvider.getInjector().getDrawableLayerResolver(); } public LiveWallpaperThumbAsset(Context context, android.app.WallpaperInfo info, Uri uri) { @@ -114,7 +123,25 @@ public class LiveWallpaperThumbAsset extends Asset { @Override public void decodeRawDimensions(Activity unused, DimensionsReceiver receiver) { - receiver.onDimensionsDecoded(null); + // TODO(b/277166654): Reuse the logic for all thumb asset decoding + sExecutorService.execute(() -> { + Bitmap result = null; + Drawable thumb = mInfo.loadThumbnail(mContext.getPackageManager()); + if (thumb instanceof BitmapDrawable) { + result = ((BitmapDrawable) thumb).getBitmap(); + } else if (thumb instanceof LayerDrawable) { + Drawable layer = mLayerResolver.resolveLayer((LayerDrawable) thumb); + if (layer instanceof BitmapDrawable) { + result = ((BitmapDrawable) layer).getBitmap(); + } + } + final Bitmap lr = result; + new Handler(Looper.getMainLooper()).post( + () -> + receiver.onDimensionsDecoded( + lr == null ? null : new Point(lr.getWidth(), lr.getHeight())) + ); + }); } @Override diff --git a/src/com/android/wallpaper/config/BaseFlags.kt b/src/com/android/wallpaper/config/BaseFlags.kt index 37f3d6e0..ffd76c69 100644 --- a/src/com/android/wallpaper/config/BaseFlags.kt +++ b/src/com/android/wallpaper/config/BaseFlags.kt @@ -16,24 +16,55 @@ package com.android.wallpaper.config import android.content.Context -import android.os.SystemProperties +import com.android.systemui.shared.customization.data.content.CustomizationProviderClient import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking abstract class BaseFlags { + var customizationProviderClient: CustomizationProviderClient? = null open fun isStagingBackdropContentEnabled() = false - open fun isEnableWallpaperEffect() = false - fun isMonochromaticFlagEnabled() = - SystemProperties.getBoolean("persist.sysui.monochromatic", false) - open fun isEnableEffectOnMultiplePanel() = false - open fun isFullscreenWallpaperPreview() = false - fun isUseRevampedUi(context: Context): Boolean { - return runBlocking { CustomizationProviderClientImpl(context, Dispatchers.IO).queryFlags() } + open fun isWallpaperEffectEnabled() = false + open fun isFullscreenWallpaperPreviewEnabled(context: Context): Boolean { + return runBlocking { getCustomizationProviderClient(context).queryFlags() } + .firstOrNull { flag -> + flag.name == Contract.FlagsTable.FLAG_NAME_WALLPAPER_FULLSCREEN_PREVIEW + } + ?.value == true + } + fun isUseRevampedUiEnabled(context: Context): Boolean { + return runBlocking { getCustomizationProviderClient(context).queryFlags() } .firstOrNull { flag -> flag.name == Contract.FlagsTable.FLAG_NAME_REVAMPED_WALLPAPER_UI } ?.value == true } + fun isCustomClocksEnabled(context: Context): Boolean { + return runBlocking { getCustomizationProviderClient(context).queryFlags() } + .firstOrNull { flag -> + flag.name == Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED + } + ?.value == true + } + fun isMonochromaticThemeEnabled(context: Context): Boolean { + return runBlocking { getCustomizationProviderClient(context).queryFlags() } + .firstOrNull { flag -> flag.name == Contract.FlagsTable.FLAG_NAME_MONOCHROMATIC_THEME } + ?.value == true + } + + fun isAIWallpaperEnabled(context: Context): Boolean { + return runBlocking { getCustomizationProviderClient(context).queryFlags() } + .firstOrNull { flag -> + flag.name == Contract.FlagsTable.FLAG_NAME_WALLPAPER_PICKER_UI_FOR_AIWP + } + ?.value == true + } + + private fun getCustomizationProviderClient(context: Context): CustomizationProviderClient { + return customizationProviderClient + ?: CustomizationProviderClientImpl(context, Dispatchers.IO).also { + customizationProviderClient = it + } + } } diff --git a/src/com/android/wallpaper/effects/EffectsController.java b/src/com/android/wallpaper/effects/EffectsController.java index 8c745718..c1e9a145 100644 --- a/src/com/android/wallpaper/effects/EffectsController.java +++ b/src/com/android/wallpaper/effects/EffectsController.java @@ -15,6 +15,7 @@ */ package com.android.wallpaper.effects; +import android.content.Context; import android.net.Uri; import android.os.Bundle; @@ -22,6 +23,11 @@ import android.os.Bundle; * Utility class to provide methods to generate effects for the wallpaper. */ public abstract class EffectsController { + public static final int ERROR_ORIGINAL_DESTROY_CONTROLLER = -16; + public static final int ERROR_ORIGINAL_FINISH_ONGOING_SERVICE = -8; + public static final int ERROR_ORIGINAL_SERVICE_DISCONNECT = -4; + public static final int ERROR_ORIGINAL_TIME_OUT = -2; + public static final int RESULT_ORIGINAL_UNKNOWN = -1; public static final int RESULT_SUCCESS = 0; public static final int RESULT_ERROR_TRY_ANOTHER_PHOTO = 1; @@ -76,6 +82,14 @@ public abstract class EffectsController { } /** + * Triggers the effect. + * + * @param context the context + */ + public void triggerEffect(Context context) { + } + + /** * Interface to listen to different key moments of the connection with the Effects Service. */ public interface EffectsServiceListener { @@ -91,4 +105,14 @@ public abstract class EffectsController { void onEffectFinished(EffectEnumInterface effect, Bundle bundle, int error, int originalStatusCode, String errorMessage); } + + /** + * Gets whether the effect triggering is successful or not. + * + * @return whether the effect triggering is successful or not. + */ + public boolean isEffectTriggered() { + return false; + } + } diff --git a/src/com/android/wallpaper/model/Category.java b/src/com/android/wallpaper/model/Category.java index a182ea4e..beb349fc 100755 --- a/src/com/android/wallpaper/model/Category.java +++ b/src/com/android/wallpaper/model/Category.java @@ -154,6 +154,13 @@ public abstract class Category { return false; } + /** + * Returns whether this category supports content that can be added or removed dynamically. + */ + public boolean supportsWallpaperSetUpdates() { + return false; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof Category)) return false; diff --git a/src/com/android/wallpaper/model/CustomizationSectionController.java b/src/com/android/wallpaper/model/CustomizationSectionController.java deleted file mode 100644 index 58ef178b..00000000 --- a/src/com/android/wallpaper/model/CustomizationSectionController.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2021 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.model; - -import android.content.Context; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; - -import com.android.wallpaper.picker.SectionView; - -/** - * The interface for the behavior of section in the customization picker. - * - * @param <T> the {@link SectionView} to create for the section - */ -public interface CustomizationSectionController<T extends SectionView> { - - /** Interface for customization section navigation. */ - interface CustomizationSectionNavigationController { - /** Navigates to the given {@code fragment}. */ - void navigateTo(Fragment fragment); - - /** Navigates to a {@code fragment} that maps to the given destination ID. */ - void navigateTo(String destinationId); - } - - /** Returns {@code true} if the customization section is available. */ - boolean isAvailable(@Nullable Context context); - - /** - * Returns a newly created {@link SectionView} for the section. - * - * @param context The {@link Context} to inflate view. - * @param isOnLockScreen Whether we are on the lock screen. - */ - default T createView(Context context, boolean isOnLockScreen) { - return createView(context); - } - - /** - * Returns a newly created {@link SectionView} for the section. - * - * @param context the {@link Context} to inflate view - */ - T createView(Context context); - - /** Saves the view state for configuration changes. */ - default void onSaveInstanceState(Bundle savedInstanceState) {} - - /** Releases the controller. */ - default void release() {} - - /** Gets called when the section gets transitioned out. */ - default void onTransitionOut() {} - - /** Notifies when the screen was switched. */ - default void onScreenSwitched(boolean isOnLockScreen) {} -} diff --git a/src/com/android/wallpaper/model/CustomizationSectionController.kt b/src/com/android/wallpaper/model/CustomizationSectionController.kt new file mode 100644 index 00000000..76c140e3 --- /dev/null +++ b/src/com/android/wallpaper/model/CustomizationSectionController.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 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.model + +import android.content.Context +import android.os.Bundle +import androidx.fragment.app.Fragment +import com.android.wallpaper.picker.SectionView + +/** + * The interface for the behavior of section in the customization picker. + * + * @param <T> the [SectionView] to create for the section </T> + */ +interface CustomizationSectionController<T : SectionView> { + /** Interface for customization section navigation. */ + interface CustomizationSectionNavigationController { + /** Navigates to the given `fragment`. */ + fun navigateTo(fragment: Fragment?) + + /** Navigates to a `fragment` that maps to the given destination ID. */ + fun navigateTo(destinationId: String?) + } + + data class ViewCreationParams( + /** Whether the view is being created in the context of the lock screen tab of the UI. */ + val isOnLockScreen: Boolean = false, + /** + * Whether the view is being created in the context of a bunch of "connected" sections that + * are laid out side-by-side in a horizontal layout. + */ + val isConnectedHorizontallyToOtherSections: Boolean = false, + ) + + /** + * It means that the creation of the controller can be expensive and we should avoid recreation + * in conditions like the user switching between the home and lock screen. + */ + @JvmDefault + fun shouldRetainInstanceWhenSwitchingTabs(): Boolean { + return false + } + + /** Returns `true` if the customization section is available. */ + fun isAvailable(context: Context): Boolean + + /** + * Returns a newly created [SectionView] for the section. + * + * @param context The [Context] to inflate view. + * @param params Parameters for the creation of the view. + */ + @JvmDefault + fun createView(context: Context, params: ViewCreationParams): T { + return createView(context) + } + + /** + * Returns a newly created [SectionView] for the section. + * + * @param context the [Context] to inflate view + */ + fun createView(context: Context): T + + /** Saves the view state for configuration changes. */ + @JvmDefault fun onSaveInstanceState(savedInstanceState: Bundle) = Unit + + /** Releases the controller. */ + @JvmDefault fun release() = Unit + + /** Gets called when the section gets transitioned out. */ + @JvmDefault fun onTransitionOut() = Unit + + /** Notifies when the screen was switched. */ + @JvmDefault fun onScreenSwitched(isOnLockScreen: Boolean) = Unit +} diff --git a/src/com/android/wallpaper/model/LiveWallpaperInfo.java b/src/com/android/wallpaper/model/LiveWallpaperInfo.java index 47bf89af..bc1f3668 100755 --- a/src/com/android/wallpaper/model/LiveWallpaperInfo.java +++ b/src/com/android/wallpaper/model/LiveWallpaperInfo.java @@ -446,4 +446,14 @@ public class LiveWallpaperInfo extends WallpaperInfo { public String getWallpaperId() { return mInfo.getServiceName(); } + + /** + * Returns true if this wallpaper is currently applied. + */ + public boolean isApplied(android.app.WallpaperInfo currentWallpaper) { + return getWallpaperComponent() != null + && currentWallpaper != null + && TextUtils.equals(getWallpaperComponent().getServiceName(), + currentWallpaper.getServiceName()); + } } diff --git a/src/com/android/wallpaper/model/LiveWallpaperMetadata.java b/src/com/android/wallpaper/model/LiveWallpaperMetadata.java new file mode 100644 index 00000000..6b0dd3a8 --- /dev/null +++ b/src/com/android/wallpaper/model/LiveWallpaperMetadata.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 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.model; + +import android.app.WallpaperInfo; + +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Live wallpaper-specific wrapper for user-facing wallpaper metadata. + */ +public class LiveWallpaperMetadata extends WallpaperMetadata { + public LiveWallpaperMetadata(android.app.WallpaperInfo wallpaperComponent) { + super(null, null, 0, 0, null, null, wallpaperComponent); + } + + @Override + public List<String> getAttributions() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Override + public String getActionUrl() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Override + public int getActionLabelRes() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Override + public int getActionIconRes() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Override + public String getCollectionId() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Nullable + @Override + public String getBackingFileName() { + throw new UnsupportedOperationException("Not implemented for live wallpapers"); + } + + @Override + public WallpaperInfo getWallpaperComponent() { + return mWallpaperComponent; + } +} diff --git a/src/com/android/wallpaper/model/SetWallpaperViewModel.java b/src/com/android/wallpaper/model/SetWallpaperViewModel.java index efd55d39..fcba06ee 100644 --- a/src/com/android/wallpaper/model/SetWallpaperViewModel.java +++ b/src/com/android/wallpaper/model/SetWallpaperViewModel.java @@ -47,7 +47,7 @@ public class SetWallpaperViewModel extends ViewModel { SetWallpaperViewModel viewModel = provider.get(SetWallpaperViewModel.class); return new SetWallpaperCallback() { @Override - public void onSuccess(WallpaperInfo wallpaperInfo) { + public void onSuccess(WallpaperInfo wallpaperInfo, @Destination int destination) { Log.d(TAG, "SetWallpaperCallback success"); viewModel.mStatus.setValue(SetWallpaperStatus.SUCCESS); } diff --git a/src/com/android/wallpaper/model/WallpaperColorsViewModel.kt b/src/com/android/wallpaper/model/WallpaperColorsViewModel.kt index 3d5b7715..8fc2a919 100644 --- a/src/com/android/wallpaper/model/WallpaperColorsViewModel.kt +++ b/src/com/android/wallpaper/model/WallpaperColorsViewModel.kt @@ -16,19 +16,52 @@ package com.android.wallpaper.model import android.app.WallpaperColors +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow -/** ViewModel class to keep track of WallpaperColors for the current wallpaper */ -class WallpaperColorsViewModel : ViewModel() { +/** + * ViewModel class to keep track of WallpaperColors for the current wallpaper + * + * TODO (b/269451870): Rename to WallpaperColorsRepository + */ +class WallpaperColorsViewModel { - /** WallpaperColors for the currently set home wallpaper */ - val homeWallpaperColors: MutableLiveData<WallpaperColors> by lazy { + /** + * WallpaperColors exposed as live data to allow Java integration + * + * TODO (b/262924584): Remove after ColorSectionController2 & ColorCustomizationManager refactor + */ + private val _homeWallpaperColorsLiveData: MutableLiveData<WallpaperColors> by lazy { MutableLiveData<WallpaperColors>() } + val homeWallpaperColorsLiveData: LiveData<WallpaperColors> = _homeWallpaperColorsLiveData + private val _lockWallpaperColorsLiveData: MutableLiveData<WallpaperColors> by lazy { + MutableLiveData<WallpaperColors>() + } + val lockWallpaperColorsLiveData: LiveData<WallpaperColors> = _lockWallpaperColorsLiveData + private val _homeWallpaperColors = MutableStateFlow<WallpaperColors?>(null) + /** WallpaperColors for the currently set home wallpaper */ + val homeWallpaperColors: StateFlow<WallpaperColors?> = _homeWallpaperColors.asStateFlow() + + private val _lockWallpaperColors = MutableStateFlow<WallpaperColors?>(null) /** WallpaperColors for the currently set lock wallpaper */ - val lockWallpaperColors: MutableLiveData<WallpaperColors> by lazy { - MutableLiveData<WallpaperColors>() + val lockWallpaperColors: StateFlow<WallpaperColors?> = _lockWallpaperColors.asStateFlow() + + fun setHomeWallpaperColors(colors: WallpaperColors?) { + _homeWallpaperColors.value = colors + if (colors != _homeWallpaperColorsLiveData.value) { + _homeWallpaperColorsLiveData.value = colors + } + } + + fun setLockWallpaperColors(colors: WallpaperColors?) { + _lockWallpaperColors.value = colors + if (colors != _lockWallpaperColorsLiveData.value) { + _lockWallpaperColorsLiveData.value = colors + } } } diff --git a/src/com/android/wallpaper/model/WallpaperInfo.java b/src/com/android/wallpaper/model/WallpaperInfo.java index 0fc0d275..761e62f6 100755 --- a/src/com/android/wallpaper/model/WallpaperInfo.java +++ b/src/com/android/wallpaper/model/WallpaperInfo.java @@ -88,6 +88,13 @@ public abstract class WallpaperInfo implements Parcelable { } /** + * Returns the content description for this wallpaper, or null if none exists. + */ + public String getContentDescription(Context context) { + return null; + } + + /** * @return The available attributions for this wallpaper, as a list of strings. These represent * the author / website or any other attribution required to be displayed for this wallpaper * regarding authorship, ownership, etc. diff --git a/src/com/android/wallpaper/model/WallpaperMetadata.java b/src/com/android/wallpaper/model/WallpaperMetadata.java index cd24796f..2e6b2734 100755 --- a/src/com/android/wallpaper/model/WallpaperMetadata.java +++ b/src/com/android/wallpaper/model/WallpaperMetadata.java @@ -32,7 +32,7 @@ public class WallpaperMetadata { private final String mActionUrl; private final String mCollectionId; private final String mBackingFileName; - private final android.app.WallpaperInfo mWallpaperComponent; + protected final android.app.WallpaperInfo mWallpaperComponent; @StringRes private final int mActionLabelRes; @DrawableRes private final int mActionIconRes; @@ -101,6 +101,6 @@ public class WallpaperMetadata { * describes an image wallpaper. */ public WallpaperInfo getWallpaperComponent() { - return mWallpaperComponent; + throw new UnsupportedOperationException("Not implemented for static wallpapers"); } } diff --git a/src/com/android/wallpaper/model/WallpaperSectionController.java b/src/com/android/wallpaper/model/WallpaperSectionController.java index cf07e76c..d61330e2 100644 --- a/src/com/android/wallpaper/model/WallpaperSectionController.java +++ b/src/com/android/wallpaper/model/WallpaperSectionController.java @@ -26,6 +26,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.graphics.RenderEffect; +import android.graphics.Shader.TileMode; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; @@ -46,6 +48,7 @@ import androidx.core.widget.ContentLoadingProgressBar; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; import androidx.lifecycle.OnLifecycleEvent; import com.android.wallpaper.R; @@ -63,6 +66,7 @@ import com.android.wallpaper.picker.WorkspaceSurfaceHolderCallback; import com.android.wallpaper.util.DisplayUtils; import com.android.wallpaper.util.PreviewUtils; import com.android.wallpaper.util.ResourceUtils; +import com.android.wallpaper.util.VideoWallpaperUtils; import com.android.wallpaper.util.WallpaperConnection; import com.android.wallpaper.util.WallpaperSurfaceCallback; import com.android.wallpaper.widget.LockScreenPreviewer; @@ -70,7 +74,9 @@ import com.android.wallpaper.widget.LockScreenPreviewer; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; -/** The class to control the wallpaper section view. */ +/** + * The class to control the wallpaper section view. + */ public class WallpaperSectionController implements CustomizationSectionController<WallpaperSectionView>, LifecycleObserver { @@ -85,12 +91,15 @@ public class WallpaperSectionController implements private WorkspaceSurfaceHolderCallback mWorkspaceSurfaceCallback; private SurfaceView mHomeWallpaperSurface; private WallpaperSurfaceCallback mHomeWallpaperSurfaceCallback; + private ImageView mHomeFadeInScrim; private SurfaceView mLockWallpaperSurface; private WallpaperSurfaceCallback mLockWallpaperSurfaceCallback; private CardView mLockscreenPreviewCard; private ViewGroup mLockPreviewContainer; + private ImageView mLockFadeInScrim; private ContentLoadingProgressBar mLockscreenPreviewProgress; - private WallpaperConnection mWallpaperConnection; + private WallpaperConnection mHomeWallpaperConnection; + private WallpaperConnection mLockWallpaperConnection; // The wallpaper information which is currently shown on the home preview. private WallpaperInfo mHomePreviewWallpaperInfo; @@ -104,7 +113,8 @@ public class WallpaperSectionController implements private final LifecycleOwner mLifecycleOwner; private final PermissionRequester mPermissionRequester; private final WallpaperColorsViewModel mWallpaperColorsViewModel; - private final WorkspaceViewModel mWorkspaceViewModel; + @Nullable + private final LiveData<Boolean> mOnThemingChanged; private final CustomizationSectionNavigationController mSectionNavigationController; private final WallpaperPreviewNavigator mWallpaperPreviewNavigator; private final Bundle mSavedInstanceState; @@ -112,7 +122,7 @@ public class WallpaperSectionController implements public WallpaperSectionController(Activity activity, LifecycleOwner lifecycleOwner, PermissionRequester permissionRequester, WallpaperColorsViewModel colorsViewModel, - WorkspaceViewModel workspaceViewModel, + @Nullable LiveData<Boolean> onThemingChanged, CustomizationSectionNavigationController sectionNavigationController, WallpaperPreviewNavigator wallpaperPreviewNavigator, Bundle savedInstanceState, @@ -122,7 +132,7 @@ public class WallpaperSectionController implements mPermissionRequester = permissionRequester; mAppContext = mActivity.getApplicationContext(); mWallpaperColorsViewModel = colorsViewModel; - mWorkspaceViewModel = workspaceViewModel; + mOnThemingChanged = onThemingChanged; mSectionNavigationController = sectionNavigationController; mWallpaperPreviewNavigator = wallpaperPreviewNavigator; mSavedInstanceState = savedInstanceState; @@ -132,27 +142,26 @@ public class WallpaperSectionController implements @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @MainThread public void onResume() { - refreshCurrentWallpapers(/* forceRefresh= */ mSavedInstanceState == null); - if (mWallpaperConnection != null) { - mWallpaperConnection.setVisibility(true); - } + refreshCurrentWallpapers(/* forceRefresh= */ true); + updateLivePreviewVisibility(true); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @MainThread public void onPause() { - if (mWallpaperConnection != null) { - mWallpaperConnection.setVisibility(false); - } + updateLivePreviewVisibility(false); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) @MainThread public void onStop() { - if (mWallpaperConnection != null) { - mWallpaperConnection.disconnect(); - mWallpaperConnection = null; - } + disconnectHomeLiveWallpaper(); + disconnectLockLiveWallpaper(); + } + + @Override + public boolean shouldRetainInstanceWhenSwitchingTabs() { + return true; } @Override @@ -174,6 +183,7 @@ public class WallpaperSectionController implements new PreviewUtils( mAppContext, mAppContext.getString(R.string.grid_control_metadata_name))); mHomeWallpaperSurface = mHomePreviewCard.findViewById(R.id.wallpaper_surface); + mHomeFadeInScrim = mHomePreviewCard.findViewById(R.id.wallpaper_fadein_scrim); Future<ColorInfo> colorFuture = CompletableFuture.completedFuture( new ColorInfo(/* wallpaperColors= */ null, @@ -183,7 +193,7 @@ public class WallpaperSectionController implements mHomeWallpaperSurface, colorFuture, () -> { if (mHomePreviewWallpaperInfo != null) { maybeLoadThumbnail(mHomePreviewWallpaperInfo, mHomeWallpaperSurfaceCallback, - mDisplayUtils.isOnWallpaperDisplay(mActivity)); + mDisplayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(mActivity), true); } }); @@ -194,11 +204,12 @@ public class WallpaperSectionController implements R.id.wallpaper_preview_spinner); mLockscreenPreviewCard.findViewById(R.id.workspace_surface).setVisibility(View.GONE); mLockWallpaperSurface = mLockscreenPreviewCard.findViewById(R.id.wallpaper_surface); + mLockFadeInScrim = mLockscreenPreviewCard.findViewById(R.id.wallpaper_fadein_scrim); mLockWallpaperSurfaceCallback = new WallpaperSurfaceCallback(mActivity, mLockscreenPreviewCard, mLockWallpaperSurface, colorFuture, () -> { if (mLockPreviewWallpaperInfo != null) { maybeLoadThumbnail(mLockPreviewWallpaperInfo, mLockWallpaperSurfaceCallback, - mDisplayUtils.isOnWallpaperDisplay(mActivity)); + mDisplayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(mActivity), false); } }); mLockPreviewContainer = mLockscreenPreviewCard.findViewById( @@ -218,14 +229,39 @@ public class WallpaperSectionController implements wallpaperSectionView.findViewById(R.id.wallpaper_picker_entry).setOnClickListener( v -> mSectionNavigationController.navigateTo(new CategorySelectorFragment())); - mWorkspaceViewModel.getUpdateWorkspace().observe(mLifecycleOwner, update -> - updateWorkspacePreview(mWorkspaceSurface, mWorkspaceSurfaceCallback, - mWallpaperColorsViewModel.getHomeWallpaperColors().getValue()) - ); + if (mOnThemingChanged != null) { + mOnThemingChanged.observe(mLifecycleOwner, update -> + updateWorkspacePreview(mWorkspaceSurface, mWorkspaceSurfaceCallback, + mWallpaperColorsViewModel.getHomeWallpaperColors().getValue()) + ); + } return wallpaperSectionView; } + private void updateLivePreviewVisibility(boolean visible) { + if (mHomeWallpaperConnection != null) { + mHomeWallpaperConnection.setVisibility(visible); + } + if (mLockWallpaperConnection != null) { + mLockWallpaperConnection.setVisibility(visible); + } + } + + private void disconnectHomeLiveWallpaper() { + if (mHomeWallpaperConnection != null) { + mHomeWallpaperConnection.disconnect(); + mHomeWallpaperConnection = null; + } + } + + private void disconnectLockLiveWallpaper() { + if (mLockWallpaperConnection != null) { + mLockWallpaperConnection.disconnect(); + mLockWallpaperConnection = null; + } + } + private void updateWorkspacePreview(SurfaceView workspaceSurface, WorkspaceSurfaceHolderCallback callback, @Nullable WallpaperColors colors) { // Reattach SurfaceView to trigger #surfaceCreated to update preview for different option. @@ -234,7 +270,9 @@ public class WallpaperSectionController implements parent.removeView(workspaceSurface); if (callback != null) { callback.resetLastSurface(); + callback.setHideBottomRow(false); callback.setWallpaperColors(colors); + callback.maybeRenderPreview(); } parent.addView(workspaceSurface, viewIndex); } @@ -374,6 +412,18 @@ public class WallpaperSectionController implements } onLockWallpaperColorsChanged(lockColors); + + // If we need to do the scrim fade, show the scrim first. + if (VideoWallpaperUtils.needsFadeIn(mHomePreviewWallpaperInfo)) { + mHomeFadeInScrim.animate().cancel(); + mHomeFadeInScrim.setAlpha(1f); + mHomeFadeInScrim.setVisibility(View.VISIBLE); + } + if (VideoWallpaperUtils.needsFadeIn(mLockPreviewWallpaperInfo)) { + mLockFadeInScrim.animate().cancel(); + mLockFadeInScrim.setAlpha(1f); + mLockFadeInScrim.setVisibility(View.VISIBLE); + } }, forceRefresh); } @@ -394,15 +444,24 @@ public class WallpaperSectionController implements // Load thumb regardless of live wallpaper to make sure we have a placeholder while // the live wallpaper initializes in that case. maybeLoadThumbnail(wallpaperInfo, surfaceCallback, - mDisplayUtils.isOnWallpaperDisplay(mActivity)); - - if (isHomeWallpaper) { - if (mWallpaperConnection != null) { - mWallpaperConnection.disconnect(); - mWallpaperConnection = null; + mDisplayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(mActivity), isHomeWallpaper); + + WallpaperManager wallpaperManager = WallpaperManager.getInstance(mActivity); + if (wallpaperManager.isLockscreenLiveWallpaperEnabled()) { + if (isHomeWallpaper) { + disconnectHomeLiveWallpaper(); + } else { + disconnectLockLiveWallpaper(); } if (wallpaperInfo instanceof LiveWallpaperInfo) { - setUpLiveWallpaperPreview(wallpaperInfo); + setUpLiveWallpaperPreview(wallpaperInfo, isHomeWallpaper); + } + } else { + if (isHomeWallpaper) { + disconnectHomeLiveWallpaper(); + if (wallpaperInfo instanceof LiveWallpaperInfo) { + setUpLiveWallpaperPreviewLegacy(wallpaperInfo); + } } } @@ -415,13 +474,19 @@ public class WallpaperSectionController implements @NonNull private Asset maybeLoadThumbnail(WallpaperInfo wallpaperInfo, - WallpaperSurfaceCallback surfaceCallback, boolean offsetToStart) { - ImageView imageView = surfaceCallback.getHomeImageWallpaper(); + WallpaperSurfaceCallback surfaceCallback, boolean offsetToStart, boolean isHome) { + ImageView liveThumbnailView = isHome ? mHomeFadeInScrim : mLockFadeInScrim; + ImageView imageView = VideoWallpaperUtils.needsFadeIn(wallpaperInfo) ? liveThumbnailView + : surfaceCallback.getHomeImageWallpaper(); Asset thumbAsset = wallpaperInfo.getThumbAsset(mAppContext); // Respect offsetToStart only for CurrentWallpaperAssetVN otherwise true. offsetToStart = !(thumbAsset instanceof CurrentWallpaperAssetVN) || offsetToStart; thumbAsset = new BitmapCachingAsset(mAppContext, thumbAsset); if (imageView != null && imageView.getDrawable() == null) { + if (VideoWallpaperUtils.needsFadeIn(wallpaperInfo)) { + imageView.setRenderEffect( + RenderEffect.createBlurEffect(50f, 50f, TileMode.CLAMP)); + } thumbAsset.loadPreviewImage(mActivity, imageView, ResourceUtils.getColorAttr(mActivity, android.R.attr.colorSecondary), offsetToStart); @@ -434,7 +499,7 @@ public class WallpaperSectionController implements mWallpaperColorsViewModel.getHomeWallpaperColors().getValue())) { return; } - mWallpaperColorsViewModel.getHomeWallpaperColors().setValue(wallpaperColors); + mWallpaperColorsViewModel.setHomeWallpaperColors(wallpaperColors); } private void onLockWallpaperColorsChanged(WallpaperColors wallpaperColors) { @@ -442,20 +507,69 @@ public class WallpaperSectionController implements mWallpaperColorsViewModel.getLockWallpaperColors().getValue())) { return; } - mWallpaperColorsViewModel.getLockWallpaperColors().setValue(wallpaperColors); + mWallpaperColorsViewModel.setLockWallpaperColors(wallpaperColors); if (mLockScreenPreviewer != null) { mLockScreenPreviewer.setColor(wallpaperColors); } } - private void setUpLiveWallpaperPreview(WallpaperInfo homeWallpaper) { + private void setUpLiveWallpaperPreview(WallpaperInfo wallpaper, boolean isHomeWallpaper) { + if (!isActivityAlive() || !WallpaperConnection.isPreviewAvailable()) { + return; + } + + final boolean isHomeBoth = (mHomePreviewWallpaperInfo == mLockPreviewWallpaperInfo); + if (isHomeBoth && !isHomeWallpaper) { + // If home and lock are the same the preview is handled by mirroring the home preview, + // so the lock preview is a no-op. + return; + } + + final SurfaceView mainSurface = + isHomeWallpaper ? mHomeWallpaperSurface : mLockWallpaperSurface; + final SurfaceView mirrorSurface = isHomeBoth ? mLockWallpaperSurface : null; + final WallpaperConnection connection = new WallpaperConnection( + getWallpaperIntent(wallpaper.getWallpaperComponent()), mActivity, + new WallpaperConnection.WallpaperConnectionListener() { + @Override + public void onWallpaperColorsChanged(WallpaperColors colors, int displayId) { + if (isHomeWallpaper) { + onHomeWallpaperColorsChanged(colors); + if (isHomeBoth && mLockScreenPreviewer != null) { + mLockScreenPreviewer.setColor(colors); + onLockWallpaperColorsChanged(colors); + } + } else { + onLockWallpaperColorsChanged(colors); + } + } + }, + mainSurface, mirrorSurface); + + connection.setVisibility(true); + if (isHomeWallpaper) { + mHomeWallpaperConnection = connection; + } else { + mLockWallpaperConnection = connection; + } + mainSurface.post(() -> { + if (mHomeWallpaperConnection != null && !mHomeWallpaperConnection.connect()) { + mHomeWallpaperConnection = null; + } + if (mLockWallpaperConnection != null && !mLockWallpaperConnection.connect()) { + mLockWallpaperConnection = null; + } + }); + } + + private void setUpLiveWallpaperPreviewLegacy(WallpaperInfo homeWallpaper) { if (!isActivityAlive()) { return; } if (WallpaperConnection.isPreviewAvailable()) { final boolean isLockLive = mLockPreviewWallpaperInfo instanceof LiveWallpaperInfo; - mWallpaperConnection = new WallpaperConnection( + mHomeWallpaperConnection = new WallpaperConnection( getWallpaperIntent(homeWallpaper.getWallpaperComponent()), mActivity, new WallpaperConnection.WallpaperConnectionListener() { @Override @@ -467,13 +581,29 @@ public class WallpaperSectionController implements } onHomeWallpaperColorsChanged(colors); } + + @Override + public void onEngineShown() { + if (VideoWallpaperUtils.needsFadeIn(homeWallpaper)) { + mHomeFadeInScrim.animate().alpha(0.0f) + .setDuration(VideoWallpaperUtils.TRANSITION_MILLIS) + .withEndAction(() -> mHomeFadeInScrim.setVisibility( + View.INVISIBLE)); + if (isLockLive) { + mLockFadeInScrim.animate().alpha(0.0f) + .setDuration(VideoWallpaperUtils.TRANSITION_MILLIS) + .withEndAction(() -> mLockFadeInScrim.setVisibility( + View.INVISIBLE)); + } + } + } }, mHomeWallpaperSurface, isLockLive ? mLockWallpaperSurface : null); - mWallpaperConnection.setVisibility(true); + mHomeWallpaperConnection.setVisibility(true); mHomeWallpaperSurface.post(() -> { - if (mWallpaperConnection != null && !mWallpaperConnection.connect()) { - mWallpaperConnection = null; + if (mHomeWallpaperConnection != null && !mHomeWallpaperConnection.connect()) { + mHomeWallpaperConnection = null; } }); } @@ -500,6 +630,7 @@ public class WallpaperSectionController implements return !mActivity.isDestroyed() && !mActivity.isFinishing(); } + // TODO(b/276439056) Remove these animations as they have no effect private void fadeWallpaperPreview(boolean isFadeIn, int duration) { setupFade(mHomePreviewCard, mHomePreviewProgress, duration, isFadeIn); setupFade(mLockscreenPreviewCard, mLockscreenPreviewProgress, duration, isFadeIn); diff --git a/src/com/android/wallpaper/module/CustomizationSections.java b/src/com/android/wallpaper/module/CustomizationSections.java index 66ae64d1..5fa62f76 100644 --- a/src/com/android/wallpaper/module/CustomizationSections.java +++ b/src/com/android/wallpaper/module/CustomizationSections.java @@ -11,7 +11,8 @@ import com.android.wallpaper.model.CustomizationSectionController.CustomizationS import com.android.wallpaper.model.PermissionRequester; import com.android.wallpaper.model.WallpaperColorsViewModel; import com.android.wallpaper.model.WallpaperPreviewNavigator; -import com.android.wallpaper.model.WorkspaceViewModel; +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor; +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel; import com.android.wallpaper.util.DisplayUtils; import java.util.List; @@ -26,24 +27,27 @@ public interface CustomizationSections { } /** + * Currently protected under BaseFlags.isUseRevampedUi() flag. + * * Gets a new instance of the section controller list for the given {@link Screen}. * * Note that the section views will be displayed by the list ordering. * * <p>Don't keep the section controllers as singleton since they contain views. */ - List<CustomizationSectionController<?>> getSectionControllersForScreen( + List<CustomizationSectionController<?>> getRevampedUISectionControllersForScreen( Screen screen, FragmentActivity activity, LifecycleOwner lifecycleOwner, WallpaperColorsViewModel wallpaperColorsViewModel, - WorkspaceViewModel workspaceViewModel, PermissionRequester permissionRequester, WallpaperPreviewNavigator wallpaperPreviewNavigator, CustomizationSectionNavigationController sectionNavigationController, @Nullable Bundle savedInstanceState, CurrentWallpaperInfoFactory wallpaperInfoFactory, - DisplayUtils displayUtils); + DisplayUtils displayUtils, + WallpaperQuickSwitchViewModel wallpaperQuickSwitchViewModel, + WallpaperInteractor wallpaperInteractor); /** * Gets a new instance of the section controller list. @@ -56,7 +60,6 @@ public interface CustomizationSections { FragmentActivity activity, LifecycleOwner lifecycleOwner, WallpaperColorsViewModel wallpaperColorsViewModel, - WorkspaceViewModel workspaceViewModel, PermissionRequester permissionRequester, WallpaperPreviewNavigator wallpaperPreviewNavigator, CustomizationSectionNavigationController sectionNavigationController, diff --git a/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java b/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java index 9e2787fd..c9f9b267 100755 --- a/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java +++ b/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java @@ -15,12 +15,14 @@ */ package com.android.wallpaper.module; +import android.app.WallpaperManager; import android.content.Context; import androidx.annotation.Nullable; import com.android.wallpaper.compat.WallpaperManagerCompat; import com.android.wallpaper.model.CurrentWallpaperInfoVN; +import com.android.wallpaper.model.LiveWallpaperMetadata; import com.android.wallpaper.model.WallpaperInfo; import com.android.wallpaper.module.WallpaperPreferences.PresentationMode; @@ -33,6 +35,7 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF private final Context mAppContext; private final WallpaperRefresher mWallpaperRefresher; private final LiveWallpaperInfoFactory mLiveWallpaperInfoFactory; + private final WallpaperManager mWallpaperManager; // Cached copies of the currently-set WallpaperInfo(s) and presentation mode. private WallpaperInfo mHomeWallpaper; @@ -46,6 +49,7 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF Injector injector = InjectorProvider.getInjector(); mWallpaperRefresher = injector.getWallpaperRefresher(mAppContext); mLiveWallpaperInfoFactory = injector.getLiveWallpaperInfoFactory(mAppContext); + mWallpaperManager = WallpaperManager.getInstance(context); } @Override @@ -68,7 +72,10 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF mWallpaperRefresher.refresh( (homeWallpaperMetadata, lockWallpaperMetadata, presentationMode) -> { WallpaperInfo homeWallpaper; - if (homeWallpaperMetadata.getWallpaperComponent() == null) { + if (homeWallpaperMetadata instanceof LiveWallpaperMetadata) { + homeWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo( + homeWallpaperMetadata.getWallpaperComponent()); + } else { homeWallpaper = new CurrentWallpaperInfoVN( homeWallpaperMetadata.getAttributions(), homeWallpaperMetadata.getActionUrl(), @@ -76,21 +83,24 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF homeWallpaperMetadata.getActionIconRes(), homeWallpaperMetadata.getCollectionId(), WallpaperManagerCompat.FLAG_SYSTEM); - } else { - homeWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo( - homeWallpaperMetadata.getWallpaperComponent()); } WallpaperInfo lockWallpaper = null; if (lockWallpaperMetadata != null) { - lockWallpaper = new CurrentWallpaperInfoVN( - lockWallpaperMetadata.getAttributions(), - lockWallpaperMetadata.getActionUrl(), - lockWallpaperMetadata.getActionLabelRes(), - lockWallpaperMetadata.getActionIconRes(), - lockWallpaperMetadata.getCollectionId(), - WallpaperManagerCompat.FLAG_LOCK); + + if (lockWallpaperMetadata instanceof LiveWallpaperMetadata) { + lockWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo( + lockWallpaperMetadata.getWallpaperComponent()); + } else { + lockWallpaper = new CurrentWallpaperInfoVN( + lockWallpaperMetadata.getAttributions(), + lockWallpaperMetadata.getActionUrl(), + lockWallpaperMetadata.getActionLabelRes(), + lockWallpaperMetadata.getActionIconRes(), + lockWallpaperMetadata.getCollectionId(), + WallpaperManagerCompat.FLAG_LOCK); + } } mHomeWallpaper = homeWallpaper; diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java index 89cc09b3..fdfc9be7 100755 --- a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java +++ b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java @@ -15,6 +15,9 @@ */ package com.android.wallpaper.module; +import static android.app.WallpaperManager.FLAG_LOCK; +import static android.app.WallpaperManager.FLAG_SYSTEM; + import android.annotation.SuppressLint; import android.app.Activity; import android.app.WallpaperColors; @@ -448,7 +451,8 @@ public class DefaultWallpaperPersister implements WallpaperPersister { int offsetY = Math.max(0, -(screenSize.y / 2 - scaledCenter.y)); Rect cropRect = WallpaperCropUtils.calculateCropRect(mAppContext, minWallpaperZoom, - wallpaperSize, defaultCropSurfaceSize, screenSize, offsetX, offsetY); + wallpaperSize, defaultCropSurfaceSize, screenSize, offsetX, + offsetY, /* cropExtraWidth= */ true); Rect scaledCropRect = new Rect( (int) Math.floor((float) cropRect.left / minWallpaperZoom), @@ -467,9 +471,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister { int wallpaperId = setBitmapToWallpaperManagerCompat(wallpaperBitmap, /* allowBackup */ false, whichWallpaper); if (wallpaperId > 0) { - mWallpaperPreferences.storeLatestHomeWallpaper(String.valueOf(wallpaperId), - attributions, actionUrl, collectionId, wallpaperBitmap, - WallpaperColors.fromBitmap(wallpaperBitmap)); + mWallpaperPreferences.storeLatestWallpaper(whichWallpaper, + String.valueOf(wallpaperId), attributions, actionUrl, collectionId, + wallpaperBitmap, WallpaperColors.fromBitmap(wallpaperBitmap)); } return wallpaperId; } @@ -532,7 +536,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister { } @Override - public void onLiveWallpaperSet() { + public void onLiveWallpaperSet(@Destination int destination) { android.app.WallpaperInfo currentWallpaperComponent = mWallpaperManager.getWallpaperInfo(); android.app.WallpaperInfo previewedWallpaperComponent = mWallpaperInfoInPreview != null ? mWallpaperInfoInPreview.getWallpaperComponent() : null; @@ -541,13 +545,14 @@ public class DefaultWallpaperPersister implements WallpaperPersister { // WallpaperInfo which was last previewed, then do nothing and nullify last previewed // wallpaper. if (currentWallpaperComponent == null || previewedWallpaperComponent == null - || !currentWallpaperComponent.getPackageName() - .equals(previewedWallpaperComponent.getPackageName())) { + || !currentWallpaperComponent.getServiceName() + .equals(previewedWallpaperComponent.getServiceName())) { mWallpaperInfoInPreview = null; return; } - setLiveWallpaperMetadata(); + setLiveWallpaperMetadata(mWallpaperInfoInPreview, mWallpaperInfoInPreview.getEffectNames(), + destination); } /** @@ -572,30 +577,29 @@ public class DefaultWallpaperPersister implements WallpaperPersister { return isLockWallpaperSet; } - /** - * Sets the live wallpaper's metadata on SharedPreferences. - */ - private void setLiveWallpaperMetadata() { - android.app.WallpaperInfo previewedWallpaperComponent = - mWallpaperInfoInPreview.getWallpaperComponent(); + @Override + public void setLiveWallpaperMetadata(WallpaperInfo wallpaperInfo, String effects, + @Destination int destination) { + android.app.WallpaperInfo component = wallpaperInfo.getWallpaperComponent(); + + if (destination == WallpaperPersister.DEST_HOME_SCREEN + || destination == WallpaperPersister.DEST_BOTH) { + mWallpaperPreferences.clearHomeWallpaperMetadata(); + mWallpaperPreferences.setHomeWallpaperServiceName(component.getServiceName()); + mWallpaperPreferences.setHomeWallpaperEffects(effects); + + // Since rotation affects home screen only, disable it when setting home live wp + mWallpaperPreferences.setWallpaperPresentationMode( + WallpaperPreferences.PRESENTATION_MODE_STATIC); + mWallpaperPreferences.clearDailyRotations(); + } - mWallpaperPreferences.clearHomeWallpaperMetadata(); - // NOTE: We explicitly do not also clear the lock wallpaper metadata. Since the user may - // have set the live wallpaper on the home screen only, we leave the lock wallpaper metadata - // intact. If the user has set the live wallpaper for both home and lock screens, then the - // WallpaperRefresher will pick up on that and update the preferences later. - mWallpaperPreferences - .setHomeWallpaperAttributions(mWallpaperInfoInPreview.getAttributions(mAppContext)); - mWallpaperPreferences.setHomeWallpaperPackageName( - previewedWallpaperComponent.getPackageName()); - mWallpaperPreferences.setHomeWallpaperServiceName( - previewedWallpaperComponent.getServiceName()); - mWallpaperPreferences.setHomeWallpaperCollectionId( - mWallpaperInfoInPreview.getCollectionId(mAppContext)); - mWallpaperPreferences.setWallpaperPresentationMode( - WallpaperPreferences.PRESENTATION_MODE_STATIC); - mWallpaperPreferences.clearDailyRotations(); - mWallpaperPreferences.setWallpaperEffects(mWallpaperInfoInPreview.getEffectNames()); + if (destination == WallpaperPersister.DEST_LOCK_SCREEN + || destination == WallpaperPersister.DEST_BOTH) { + mWallpaperPreferences.clearLockWallpaperMetadata(); + mWallpaperPreferences.setLockWallpaperServiceName(component.getServiceName()); + mWallpaperPreferences.setLockWallpaperEffects(effects); + } } private class SetWallpaperTask extends AsyncTask<Void, Void, Boolean> { @@ -725,7 +729,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister { } if (isSuccess) { - mCallback.onSuccess(mWallpaper); + mCallback.onSuccess(mWallpaper, mDestination); mWallpaperChangedNotifier.notifyWallpaperChanged(); } else { mCallback.onError(null /* throwable */); @@ -774,7 +778,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister { private void setImageWallpaperMetadata(@Destination int destination, int wallpaperId) { if (destination == DEST_HOME_SCREEN || destination == DEST_BOTH) { mWallpaperPreferences.clearHomeWallpaperMetadata(); - mWallpaperPreferences.setWallpaperEffects(null); + mWallpaperPreferences.setHomeWallpaperEffects(null); setImageWallpaperHomeMetadata(wallpaperId); // Reset presentation mode to STATIC if an individual wallpaper is set to the @@ -820,7 +824,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister { mWallpaperPreferences.setHomeWallpaperCollectionId( mWallpaper.getCollectionId(mAppContext)); mWallpaperPreferences.setHomeWallpaperRemoteId(mWallpaper.getWallpaperId()); - mWallpaperPreferences.storeLatestHomeWallpaper( + mWallpaperPreferences.storeLatestWallpaper(FLAG_SYSTEM, TextUtils.isEmpty(mWallpaper.getWallpaperId()) ? String.valueOf(bitmapHash) : mWallpaper.getWallpaperId(), mWallpaper, mBitmap, colors); @@ -843,42 +847,46 @@ public class DefaultWallpaperPersister implements WallpaperPersister { // because WallpaperManager-generated IDs are specific to a physical device and // cannot be used to identify a wallpaper image on another device after restore is // complete. - saveLockWallpaperHashCode(); + Bitmap lockBitmap = getLockWallpaperBitmap(); + if (lockBitmap != null) { + saveLockWallpaperHashCode(lockBitmap); + mWallpaperPreferences.storeLatestWallpaper(FLAG_LOCK, + TextUtils.isEmpty(mWallpaper.getWallpaperId()) + ? String.valueOf(mWallpaperPreferences.getLockWallpaperHashCode()) + : mWallpaper.getWallpaperId(), + mWallpaper, lockBitmap, WallpaperColors.fromBitmap(lockBitmap)); + } } - private void saveLockWallpaperHashCode() { - Bitmap lockBitmap = null; - + private Bitmap getLockWallpaperBitmap() { ParcelFileDescriptor parcelFd = mWallpaperManagerCompat.getWallpaperFile( WallpaperManagerCompat.FLAG_LOCK); if (parcelFd == null) { - return; + return null; } - InputStream fileStream = null; - try { - fileStream = new FileInputStream(parcelFd.getFileDescriptor()); - lockBitmap = BitmapFactory.decodeStream(fileStream); - parcelFd.close(); + try (InputStream fileStream = new FileInputStream(parcelFd.getFileDescriptor())) { + return BitmapFactory.decodeStream(fileStream); } catch (IOException e) { - Log.e(TAG, "IO exception when closing the file descriptor."); + Log.e(TAG, "IO exception when closing the file stream.", e); + return null; } finally { - if (fileStream != null) { - try { - fileStream.close(); - } catch (IOException e) { - Log.e(TAG, - "IO exception when closing the input stream for the lock screen " - + "WP."); - } + try { + parcelFd.close(); + } catch (IOException e) { + Log.e(TAG, "IO exception when closing the file descriptor.", e); } } + } + private long saveLockWallpaperHashCode(Bitmap lockBitmap) { if (lockBitmap != null) { long bitmapHash = BitmapUtils.generateHashCode(lockBitmap); mWallpaperPreferences.setLockWallpaperHashCode(bitmapHash); + return bitmapHash; } + return 0; } } } diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java b/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java index c2cd07b4..6f945a90 100755 --- a/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java +++ b/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java @@ -47,6 +47,7 @@ import java.util.TimeZone; * Default implementation that writes to and reads from SharedPreferences. */ public class DefaultWallpaperPreferences implements WallpaperPreferences { + public static final String PREFS_NAME = "wallpaper"; public static final String NO_BACKUP_PREFS_NAME = "wallpaper-nobackup"; @@ -154,10 +155,6 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences { editor.putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, mSharedPrefs.getInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, 0)); } - if (mSharedPrefs.contains(NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME)) { - editor.putString(NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, - mSharedPrefs.getString(NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, null)); - } if (mSharedPrefs.contains(NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME)) { editor.putString(NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME, mSharedPrefs.getString(NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME, null)); @@ -325,7 +322,7 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences { .apply(); mNoBackupPrefs.edit() - .remove(NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME) + .remove(NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME) .remove(NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID) .remove(NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID) .remove(NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME) @@ -335,19 +332,6 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences { } @Override - public String getHomeWallpaperPackageName() { - return mNoBackupPrefs.getString( - NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, null); - } - - @Override - public void setHomeWallpaperPackageName(String packageName) { - mNoBackupPrefs.edit().putString( - NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, packageName) - .apply(); - } - - @Override public String getHomeWallpaperServiceName() { return mNoBackupPrefs.getString( NoBackupKeys.KEY_HOME_WALLPAPER_SERVICE_NAME, null); @@ -542,6 +526,17 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences { } @Override + public String getLockWallpaperServiceName() { + return mNoBackupPrefs.getString(NoBackupKeys.KEY_LOCK_WALLPAPER_SERVICE_NAME, null); + } + + @Override + public void setLockWallpaperServiceName(String serviceName) { + mNoBackupPrefs.edit().putString(NoBackupKeys.KEY_LOCK_WALLPAPER_SERVICE_NAME, serviceName) + .apply(); + } + + @Override public void addDailyRotation(long timestamp) { String jsonString = mNoBackupPrefs.getString( NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]"); @@ -942,19 +937,32 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences { setLockWallpaperCollectionId(collectionId); setLockWallpaperRemoteId(wallpaperId); } - setWallpaperEffects(null); + setHomeWallpaperEffects(null); + } + + @Override + public String getHomeWallpaperEffects() { + return mNoBackupPrefs.getString( + NoBackupKeys.KEY_HOME_WALLPAPER_EFFECTS, null); + } + + @Override + public void setHomeWallpaperEffects(String effects) { + mNoBackupPrefs.edit().putString( + NoBackupKeys.KEY_HOME_WALLPAPER_EFFECTS, effects) + .apply(); } @Override - public String getWallpaperEffects() { + public String getLockWallpaperEffects() { return mNoBackupPrefs.getString( - NoBackupKeys.KEY_WALLPAPER_EFFECTS, null); + NoBackupKeys.KEY_LOCK_WALLPAPER_EFFECTS, null); } @Override - public void setWallpaperEffects(String effects) { + public void setLockWallpaperEffects(String effects) { mNoBackupPrefs.edit().putString( - NoBackupKeys.KEY_WALLPAPER_EFFECTS, effects) + NoBackupKeys.KEY_LOCK_WALLPAPER_EFFECTS, effects) .apply(); } diff --git a/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java b/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java index 3363d8ea..3c870280 100755 --- a/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java +++ b/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java @@ -15,6 +15,9 @@ */ package com.android.wallpaper.module; +import static com.android.wallpaper.compat.WallpaperManagerCompat.FLAG_LOCK; +import static com.android.wallpaper.compat.WallpaperManagerCompat.FLAG_SYSTEM; + import android.annotation.SuppressLint; import android.app.WallpaperManager; import android.content.Context; @@ -29,6 +32,7 @@ import android.util.Log; import com.android.wallpaper.R; import com.android.wallpaper.asset.BitmapUtils; import com.android.wallpaper.compat.WallpaperManagerCompat; +import com.android.wallpaper.model.LiveWallpaperMetadata; import com.android.wallpaper.model.WallpaperMetadata; import java.io.FileInputStream; @@ -44,6 +48,7 @@ import java.util.List; */ @SuppressLint("ServiceCast") public class DefaultWallpaperRefresher implements WallpaperRefresher { + private static final String TAG = "DefaultWPRefresher"; private final Context mAppContext; @@ -77,12 +82,13 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { */ private class GetWallpaperMetadataAsyncTask extends AsyncTask<Void, Void, List<WallpaperMetadata>> { + private final RefreshListener mListener; private final WallpaperManagerCompat mWallpaperManagerCompat; private long mCurrentHomeWallpaperHashCode; private long mCurrentLockWallpaperHashCode; - private String mSystemWallpaperPackageName; + private String mSystemWallpaperServiceName; @SuppressLint("ServiceCast") public GetWallpaperMetadataAsyncTask(RefreshListener listener) { @@ -95,18 +101,17 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { protected List<WallpaperMetadata> doInBackground(Void... unused) { List<WallpaperMetadata> wallpaperMetadatas = new ArrayList<>(); - if (!isHomeScreenMetadataCurrent() || isHomeScreenAttributionsEmpty()) { + boolean isHomeScreenStatic = mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM) == null; + if (!isHomeScreenMetadataCurrent() || (isHomeScreenStatic + && isHomeScreenAttributionsEmpty())) { mWallpaperPreferences.clearHomeWallpaperMetadata(); setFallbackHomeScreenWallpaperMetadata(); } - boolean isLockScreenWallpaperCurrentlySet = mWallpaperStatusChecker.isLockWallpaperSet( - mAppContext); + boolean isLockScreenWallpaperCurrentlySet = + mWallpaperStatusChecker.isLockWallpaperSet(mAppContext); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N - || !isLockScreenWallpaperCurrentlySet) { - - // Return only home metadata if pre-N device or lock screen wallpaper is not explicitly set. + if (mWallpaperManager.getWallpaperInfo() == null) { wallpaperMetadatas.add(new WallpaperMetadata( mWallpaperPreferences.getHomeWallpaperAttributions(), mWallpaperPreferences.getHomeWallpaperActionUrl(), @@ -114,32 +119,40 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { mWallpaperPreferences.getHomeWallpaperActionIconRes(), mWallpaperPreferences.getHomeWallpaperCollectionId(), mWallpaperPreferences.getHomeWallpaperBackingFileName(), - mWallpaperManager.getWallpaperInfo())); + null)); + } else { + wallpaperMetadatas.add( + new LiveWallpaperMetadata(mWallpaperManager.getWallpaperInfo())); + } + + // Return only home metadata if pre-N device or lock screen wallpaper is not explicitly + // set. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N + || !isLockScreenWallpaperCurrentlySet) { return wallpaperMetadatas; } - if (!isLockScreenMetadataCurrent() || isLockScreenAttributionsEmpty()) { + boolean isLockScreenStatic = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null; + if (!isLockScreenMetadataCurrent() || (isLockScreenStatic + && isLockScreenAttributionsEmpty())) { mWallpaperPreferences.clearLockWallpaperMetadata(); setFallbackLockScreenWallpaperMetadata(); } - wallpaperMetadatas.add(new WallpaperMetadata( - mWallpaperPreferences.getHomeWallpaperAttributions(), - mWallpaperPreferences.getHomeWallpaperActionUrl(), - mWallpaperPreferences.getHomeWallpaperActionLabelRes(), - mWallpaperPreferences.getHomeWallpaperActionIconRes(), - mWallpaperPreferences.getHomeWallpaperCollectionId(), - mWallpaperPreferences.getHomeWallpaperBackingFileName(), - mWallpaperManager.getWallpaperInfo())); - - wallpaperMetadatas.add(new WallpaperMetadata( - mWallpaperPreferences.getLockWallpaperAttributions(), - mWallpaperPreferences.getLockWallpaperActionUrl(), - mWallpaperPreferences.getLockWallpaperActionLabelRes(), - mWallpaperPreferences.getLockWallpaperActionIconRes(), - mWallpaperPreferences.getLockWallpaperCollectionId(), - mWallpaperPreferences.getLockWallpaperBackingFileName(), - null /* wallpaperComponent */)); + if (mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null + || !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) { + wallpaperMetadatas.add(new WallpaperMetadata( + mWallpaperPreferences.getLockWallpaperAttributions(), + mWallpaperPreferences.getLockWallpaperActionUrl(), + mWallpaperPreferences.getLockWallpaperActionLabelRes(), + mWallpaperPreferences.getLockWallpaperActionIconRes(), + mWallpaperPreferences.getLockWallpaperCollectionId(), + mWallpaperPreferences.getLockWallpaperBackingFileName(), + null)); + } else { + wallpaperMetadatas.add(new LiveWallpaperMetadata( + mWallpaperManager.getWallpaperInfo(FLAG_LOCK))); + } return wallpaperMetadatas; } @@ -147,8 +160,9 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { @Override protected void onPostExecute(List<WallpaperMetadata> metadatas) { if (metadatas.size() > 2) { - Log.e(TAG, "Got more than 2 WallpaperMetadata objects - only home and (optionally) lock " - + "are permitted."); + Log.e(TAG, + "Got more than 2 WallpaperMetadata objects - only home and (optionally) " + + "lock are permitted."); return; } @@ -157,27 +171,30 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { } /** - * Sets fallback wallpaper attributions to WallpaperPreferences when the saved metadata did not - * match the system wallpaper. For live wallpapers, loads the label (title) but for image - * wallpapers loads a generic title string. + * Sets fallback wallpaper attributions to WallpaperPreferences when the saved metadata did + * not match the system wallpaper. For live wallpapers, loads the label (title) but for + * image wallpapers loads a generic title string. */ private void setFallbackHomeScreenWallpaperMetadata() { android.app.WallpaperInfo wallpaperComponent = mWallpaperManager.getWallpaperInfo(); if (wallpaperComponent == null) { // Image wallpaper mWallpaperPreferences.setHomeWallpaperAttributions( - Arrays.asList(mAppContext.getResources().getString(R.string.fallback_wallpaper_title))); + Arrays.asList(mAppContext.getResources() + .getString(R.string.fallback_wallpaper_title))); - // Set wallpaper ID if at least N or set a hash code if an earlier version of Android. + // Set wallpaper ID if at least N or set a hash code if an earlier version of + // Android. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - mWallpaperPreferences.setHomeWallpaperManagerId(mWallpaperManagerCompat.getWallpaperId( - WallpaperManagerCompat.FLAG_SYSTEM)); + mWallpaperPreferences.setHomeWallpaperManagerId( + mWallpaperManagerCompat.getWallpaperId(FLAG_SYSTEM)); } else { - mWallpaperPreferences.setHomeWallpaperHashCode(getCurrentHomeWallpaperHashCode()); + mWallpaperPreferences.setHomeWallpaperHashCode( + getCurrentHomeWallpaperHashCode()); } } else { // Live wallpaper mWallpaperPreferences.setHomeWallpaperAttributions(Arrays.asList( wallpaperComponent.loadLabel(mAppContext.getPackageManager()).toString())); - mWallpaperPreferences.setHomeWallpaperPackageName(mSystemWallpaperPackageName); + mWallpaperPreferences.setHomeWallpaperServiceName(mSystemWallpaperServiceName); } mWallpaperPreferences.setWallpaperPresentationMode( WallpaperPreferences.PRESENTATION_MODE_STATIC); @@ -185,14 +202,15 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { /** * Sets fallback lock screen wallpaper attributions to WallpaperPreferences. This should be - * called when the saved lock screen wallpaper metadata does not match the currently set lock - * screen wallpaper. + * called when the saved lock screen wallpaper metadata does not match the currently set + * lock screen wallpaper. */ private void setFallbackLockScreenWallpaperMetadata() { mWallpaperPreferences.setLockWallpaperAttributions( - Arrays.asList(mAppContext.getResources().getString(R.string.fallback_wallpaper_title))); + Arrays.asList(mAppContext.getResources() + .getString(R.string.fallback_wallpaper_title))); mWallpaperPreferences.setLockWallpaperId(mWallpaperManagerCompat.getWallpaperId( - WallpaperManagerCompat.FLAG_LOCK)); + FLAG_LOCK)); } /** @@ -209,7 +227,8 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { * Returns whether the home screen attributions saved in WallpaperPreferences is empty. */ private boolean isHomeScreenAttributionsEmpty() { - List<String> homeScreenAttributions = mWallpaperPreferences.getHomeWallpaperAttributions(); + List<String> homeScreenAttributions = + mWallpaperPreferences.getHomeWallpaperAttributions(); return homeScreenAttributions.get(0) == null && homeScreenAttributions.get(1) == null && homeScreenAttributions.get(2) == null; @@ -217,13 +236,15 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { private long getCurrentHomeWallpaperHashCode() { if (mCurrentHomeWallpaperHashCode == 0) { - BitmapDrawable wallpaperDrawable = (BitmapDrawable) mWallpaperManagerCompat.getDrawable(); - Bitmap wallpaperBitmap = wallpaperDrawable.getBitmap(); - mCurrentHomeWallpaperHashCode = BitmapUtils.generateHashCode(wallpaperBitmap); - - // Manually request that WallpaperManager loses its reference to the current wallpaper - // bitmap, which can occupy a large memory allocation for the lifetime of the app. - mWallpaperManager.forgetLoadedWallpaper(); + BitmapDrawable wallpaperDrawable = (BitmapDrawable) + mWallpaperManagerCompat.getDrawable(); + Bitmap wallpaperBitmap = wallpaperDrawable.getBitmap(); + mCurrentHomeWallpaperHashCode = BitmapUtils.generateHashCode(wallpaperBitmap); + + // Manually request that WallpaperManager loses its reference to the current + // wallpaper bitmap, which can occupy a large memory allocation for the lifetime of + // the app. + mWallpaperManager.forgetLoadedWallpaper(); } return mCurrentHomeWallpaperHashCode; } @@ -245,7 +266,7 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { Bitmap lockBitmap = null; ParcelFileDescriptor pfd = mWallpaperManagerCompat.getWallpaperFile( - WallpaperManagerCompat.FLAG_LOCK); + FLAG_LOCK); // getWallpaperFile returns null if the lock screen isn't explicitly set, so need this // check. if (pfd != null) { @@ -262,7 +283,8 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { try { fileStream.close(); } catch (IOException e) { - Log.e(TAG, "IO exception when closing input stream for lock screen WP."); + Log.e(TAG, + "IO exception when closing input stream for lock screen WP."); } } } @@ -278,25 +300,25 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { private boolean isHomeScreenImageWallpaperCurrent() { long savedBitmapHash = mWallpaperPreferences.getHomeWallpaperHashCode(); - // Use WallpaperManager IDs to check same-ness of image wallpaper on N+ versions of Android - // only when there is no saved bitmap hash code (which could be leftover from a previous build - // of the app that did not use wallpaper IDs). + // Use WallpaperManager IDs to check same-ness of image wallpaper on N+ versions of + // Android only when there is no saved bitmap hash code (which could be leftover from a + // previous build of the app that did not use wallpaper IDs). if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && savedBitmapHash == 0) { return mWallpaperPreferences.getHomeWallpaperManagerId() - == mWallpaperManagerCompat.getWallpaperId(WallpaperManagerCompat.FLAG_SYSTEM); + == mWallpaperManagerCompat.getWallpaperId(FLAG_SYSTEM); } return savedBitmapHash == getCurrentHomeWallpaperHashCode(); } /** - * Returns whether the live wallpaper set to the system's home screen matches the metadata in - * WallpaperPreferences. + * Returns whether the live wallpaper set to the system's home screen matches the metadata + * in WallpaperPreferences. */ private boolean isHomeScreenLiveWallpaperCurrent() { - mSystemWallpaperPackageName = mWallpaperManager.getWallpaperInfo().getPackageName(); - String homeWallpaperPackageName = mWallpaperPreferences.getHomeWallpaperPackageName(); - return mSystemWallpaperPackageName.equals(homeWallpaperPackageName); + mSystemWallpaperServiceName = mWallpaperManager.getWallpaperInfo().getServiceName(); + String homeWallpaperServiceName = mWallpaperPreferences.getHomeWallpaperServiceName(); + return mSystemWallpaperServiceName.equals(homeWallpaperServiceName); } /** @@ -304,18 +326,42 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher { * current lock screen wallpaper. */ private boolean isLockScreenMetadataCurrent() { - // Check for lock wallpaper image same-ness only when there is no stored lock wallpaper hash - // code. Otherwise if there is a lock wallpaper hash code stored in + return (mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null) + ? isLockScreenImageWallpaperCurrent() + : isLockScreenLiveWallpaperCurrent(); + } + + /** + * Returns whether the image wallpaper set for the lock screen matches the metadata in + * WallpaperPreferences. + */ + private boolean isLockScreenImageWallpaperCurrent() { + // Check for lock wallpaper image same-ness only when there is no stored lock wallpaper + // hash code. Otherwise if there is a lock wallpaper hash code stored in // {@link WallpaperPreferences}, then check hash codes. long savedLockWallpaperHash = mWallpaperPreferences.getLockWallpaperHashCode(); - return (savedLockWallpaperHash == 0) - ? mWallpaperPreferences.getLockWallpaperId() - == mWallpaperManagerCompat.getWallpaperId(WallpaperManagerCompat.FLAG_LOCK) - : savedLockWallpaperHash == getCurrentLockWallpaperHashCode(); + if (savedLockWallpaperHash == 0) { + return mWallpaperPreferences.getLockWallpaperId() + == mWallpaperManagerCompat.getWallpaperId(FLAG_LOCK); + } else { + return savedLockWallpaperHash == getCurrentLockWallpaperHashCode(); + } } /** + * Returns whether the live wallpaper for the home screen matches the metadata in + * WallpaperPreferences. + */ + private boolean isLockScreenLiveWallpaperCurrent() { + String currentServiceName = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) + .getServiceName(); + String storedServiceName = mWallpaperPreferences.getLockWallpaperServiceName(); + return currentServiceName.equals(storedServiceName); + } + + + /** * Returns whether the lock screen attributions saved in WallpaperPreferences are empty. */ private boolean isLockScreenAttributionsEmpty() { diff --git a/src/com/android/wallpaper/module/Injector.kt b/src/com/android/wallpaper/module/Injector.kt index bcbf0e59..37b2c20a 100755 --- a/src/com/android/wallpaper/module/Injector.kt +++ b/src/com/android/wallpaper/module/Injector.kt @@ -15,20 +15,22 @@ */ package com.android.wallpaper.module -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri +import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import com.android.wallpaper.compat.WallpaperManagerCompat import com.android.wallpaper.config.BaseFlags import com.android.wallpaper.effects.EffectsController -import com.android.wallpaper.effects.EffectsController.EffectsServiceListener import com.android.wallpaper.model.CategoryProvider +import com.android.wallpaper.model.WallpaperColorsViewModel import com.android.wallpaper.model.WallpaperInfo import com.android.wallpaper.monitor.PerformanceMonitor import com.android.wallpaper.network.Requester import com.android.wallpaper.picker.PreviewFragment +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperSnapshotRestorer import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor import com.android.wallpaper.util.DisplayUtils @@ -46,7 +48,7 @@ interface Injector { fun getCurrentWallpaperInfoFactory(context: Context): CurrentWallpaperInfoFactory - fun getCustomizationSections(activity: Activity): CustomizationSections + fun getCustomizationSections(activity: ComponentActivity): CustomizationSections fun getDeepLinkRedirectIntent(context: Context, uri: Uri): Intent @@ -56,11 +58,11 @@ interface Injector { fun getDrawableLayerResolver(): DrawableLayerResolver - fun getEffectsController(context: Context, listener: EffectsServiceListener): EffectsController? + fun getEffectsController(context: Context): EffectsController? fun getExploreIntentChecker(context: Context): ExploreIntentChecker - fun getIndividualPickerFragment(collectionId: String): Fragment + fun getIndividualPickerFragment(context: Context, collectionId: String): Fragment fun getLiveWallpaperInfoFactory(context: Context): LiveWallpaperInfoFactory @@ -114,4 +116,10 @@ interface Injector { // Empty because we don't support undoing in WallpaperPicker2. return HashMap() } + + fun getWallpaperInteractor(context: Context): WallpaperInteractor + + fun getWallpaperSnapshotRestorer(context: Context): WallpaperSnapshotRestorer + + fun getWallpaperColorsViewModel(): WallpaperColorsViewModel } diff --git a/src/com/android/wallpaper/module/LargeScreenMultiPanesChecker.kt b/src/com/android/wallpaper/module/LargeScreenMultiPanesChecker.kt index 7e42d2da..5b4e5ec6 100644 --- a/src/com/android/wallpaper/module/LargeScreenMultiPanesChecker.kt +++ b/src/com/android/wallpaper/module/LargeScreenMultiPanesChecker.kt @@ -39,6 +39,7 @@ class LargeScreenMultiPanesChecker : MultiPanesChecker { override fun getMultiPanesIntent(intent: Intent): Intent { return Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY).apply { + intent.extras?.let { putExtras(it) } putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, VALUE_HIGHLIGHT_MENU) putExtra( EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI, diff --git a/src/com/android/wallpaper/module/WallpaperPersister.java b/src/com/android/wallpaper/module/WallpaperPersister.java index cfb3cab9..9b5cae82 100755 --- a/src/com/android/wallpaper/module/WallpaperPersister.java +++ b/src/com/android/wallpaper/module/WallpaperPersister.java @@ -167,14 +167,26 @@ public interface WallpaperPersister { * Saves attributions to WallpaperPreferences for the last previewed wallpaper if it has an * {@link android.app.WallpaperInfo} component matching the one currently set to the * {@link android.app.WallpaperManager}. + * + * @param destination Live wallpaper destination (home/lock/both) + */ + void onLiveWallpaperSet(@Destination int destination); + + /** + * Updates lie wallpaper metadata by persisting them to SharedPreferences. + * + * @param wallpaperInfo Wallpaper model for the live wallpaper + * @param effects Comma-separate list of effect (see {@link WallpaperInfo#getEffectNames}) + * @param destination Live wallpaper destination (home/lock/both) */ - void onLiveWallpaperSet(); + void setLiveWallpaperMetadata(WallpaperInfo wallpaperInfo, String effects, + @Destination int destination); /** * Interface for tracking success or failure of set wallpaper operations. */ interface SetWallpaperCallback { - void onSuccess(WallpaperInfo wallpaperInfo); + void onSuccess(WallpaperInfo wallpaperInfo, @Destination int destination); void onError(@Nullable Throwable throwable); } @@ -215,4 +227,20 @@ public interface WallpaperPersister { throw new AssertionError("Unknown @Destination"); } } + + /** + * Converts a set of {@link SetWallpaperFlags} to the corresponding {@link Destination}. + */ + @Destination + static int flagsToDestination(@SetWallpaperFlags int flags) { + if (flags == (FLAG_SYSTEM | FLAG_LOCK)) { + return DEST_BOTH; + } else if (flags == FLAG_SYSTEM) { + return DEST_HOME_SCREEN; + } else if (flags == FLAG_LOCK) { + return DEST_LOCK_SCREEN; + } else { + throw new AssertionError("Unknown @SetWallpaperFlags value"); + } + } } diff --git a/src/com/android/wallpaper/module/WallpaperPicker2Injector.kt b/src/com/android/wallpaper/module/WallpaperPicker2Injector.kt index d97e4bea..db560c4d 100755 --- a/src/com/android/wallpaper/module/WallpaperPicker2Injector.kt +++ b/src/com/android/wallpaper/module/WallpaperPicker2Injector.kt @@ -15,18 +15,18 @@ */ package com.android.wallpaper.module -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import com.android.wallpaper.compat.WallpaperManagerCompat import com.android.wallpaper.config.BaseFlags import com.android.wallpaper.effects.EffectsController -import com.android.wallpaper.effects.EffectsController.EffectsServiceListener import com.android.wallpaper.model.CategoryProvider import com.android.wallpaper.model.LiveWallpaperInfo +import com.android.wallpaper.model.WallpaperColorsViewModel import com.android.wallpaper.model.WallpaperInfo import com.android.wallpaper.monitor.PerformanceMonitor import com.android.wallpaper.network.Requester @@ -35,13 +35,20 @@ import com.android.wallpaper.picker.CustomizationPickerActivity import com.android.wallpaper.picker.ImagePreviewFragment import com.android.wallpaper.picker.LivePreviewFragment import com.android.wallpaper.picker.PreviewFragment +import com.android.wallpaper.picker.customization.data.content.WallpaperClientImpl +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperSnapshotRestorer import com.android.wallpaper.picker.individual.IndividualPickerFragment import com.android.wallpaper.picker.undo.data.repository.UndoRepository import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor +import com.android.wallpaper.settings.data.repository.SecureSettingsRepository +import com.android.wallpaper.settings.data.repository.SecureSettingsRepositoryImpl import com.android.wallpaper.util.DisplayUtils +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope -open class WallpaperPicker2Injector : Injector { +open class WallpaperPicker2Injector() : Injector { private var alarmManagerWrapper: AlarmManagerWrapper? = null private var bitmapCropper: BitmapCropper? = null private var categoryProvider: CategoryProvider? = null @@ -67,6 +74,10 @@ open class WallpaperPicker2Injector : Injector { private var wallpaperStatusChecker: WallpaperStatusChecker? = null private var flags: BaseFlags? = null private var undoInteractor: UndoInteractor? = null + private var wallpaperInteractor: WallpaperInteractor? = null + private var wallpaperSnapshotRestorer: WallpaperSnapshotRestorer? = null + private var secureSettingsRepository: SecureSettingsRepository? = null + private var wallpaperColorsViewModel: WallpaperColorsViewModel? = null @Synchronized override fun getAlarmManagerWrapper(context: Context): AlarmManagerWrapper { @@ -94,8 +105,7 @@ open class WallpaperPicker2Injector : Injector { } } - override fun getCustomizationSections(activity: Activity): CustomizationSections { - + override fun getCustomizationSections(activity: ComponentActivity): CustomizationSections { return customizationSections ?: WallpaperPickerSections().also { customizationSections = it } } @@ -123,7 +133,6 @@ open class WallpaperPicker2Injector : Injector { override fun getEffectsController( context: Context, - listener: EffectsServiceListener ): EffectsController? { return null } @@ -136,8 +145,7 @@ open class WallpaperPicker2Injector : Injector { } } - @Synchronized - override fun getIndividualPickerFragment(collectionId: String): Fragment { + override fun getIndividualPickerFragment(context: Context, collectionId: String): Fragment { return IndividualPickerFragment.newInstance(collectionId) } @@ -275,6 +283,42 @@ open class WallpaperPicker2Injector : Injector { } } + override fun getWallpaperInteractor(context: Context): WallpaperInteractor { + return wallpaperInteractor + ?: WallpaperInteractor( + repository = + WallpaperRepository( + scope = GlobalScope, + client = WallpaperClientImpl(context = context), + backgroundDispatcher = Dispatchers.IO, + ), + ) + .also { wallpaperInteractor = it } + } + + override fun getWallpaperSnapshotRestorer(context: Context): WallpaperSnapshotRestorer { + return wallpaperSnapshotRestorer + ?: WallpaperSnapshotRestorer( + scope = GlobalScope, + interactor = getWallpaperInteractor(context), + ) + .also { wallpaperSnapshotRestorer = it } + } + + protected fun getSecureSettingsRepository(context: Context): SecureSettingsRepository { + return secureSettingsRepository + ?: SecureSettingsRepositoryImpl( + contentResolver = context.contentResolver, + backgroundDispatcher = Dispatchers.IO, + ) + .also { secureSettingsRepository = it } + } + + override fun getWallpaperColorsViewModel(): WallpaperColorsViewModel { + return wallpaperColorsViewModel + ?: WallpaperColorsViewModel().also { wallpaperColorsViewModel = it } + } + companion object { /** * When this injector is overridden, this is the minimal value that should be used by diff --git a/src/com/android/wallpaper/module/WallpaperPickerSections.java b/src/com/android/wallpaper/module/WallpaperPickerSections.java index 16782ce3..a77bf2e0 100644 --- a/src/com/android/wallpaper/module/WallpaperPickerSections.java +++ b/src/com/android/wallpaper/module/WallpaperPickerSections.java @@ -12,8 +12,10 @@ import com.android.wallpaper.model.PermissionRequester; import com.android.wallpaper.model.WallpaperColorsViewModel; import com.android.wallpaper.model.WallpaperPreviewNavigator; import com.android.wallpaper.model.WallpaperSectionController; -import com.android.wallpaper.model.WorkspaceViewModel; +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor; import com.android.wallpaper.picker.customization.ui.section.ScreenPreviewSectionController; +import com.android.wallpaper.picker.customization.ui.section.WallpaperQuickSwitchSectionController; +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel; import com.android.wallpaper.util.DisplayUtils; import java.util.ArrayList; @@ -23,18 +25,19 @@ import java.util.List; public final class WallpaperPickerSections implements CustomizationSections { @Override - public List<CustomizationSectionController<?>> getSectionControllersForScreen( + public List<CustomizationSectionController<?>> getRevampedUISectionControllersForScreen( Screen screen, FragmentActivity activity, LifecycleOwner lifecycleOwner, WallpaperColorsViewModel wallpaperColorsViewModel, - WorkspaceViewModel workspaceViewModel, PermissionRequester permissionRequester, WallpaperPreviewNavigator wallpaperPreviewNavigator, CustomizationSectionNavigationController sectionNavigationController, @Nullable Bundle savedInstanceState, CurrentWallpaperInfoFactory wallpaperInfoFactory, - DisplayUtils displayUtils) { + DisplayUtils displayUtils, + WallpaperQuickSwitchViewModel wallpaperQuickSwitchViewModel, + WallpaperInteractor wallpaperInteractor) { List<CustomizationSectionController<?>> sectionControllers = new ArrayList<>(); sectionControllers.add( @@ -44,7 +47,15 @@ public final class WallpaperPickerSections implements CustomizationSections { screen, wallpaperInfoFactory, wallpaperColorsViewModel, - displayUtils)); + displayUtils, + sectionNavigationController, + wallpaperInteractor)); + sectionControllers.add( + new WallpaperQuickSwitchSectionController( + screen, + wallpaperQuickSwitchViewModel, + lifecycleOwner, + sectionNavigationController)); return sectionControllers; } @@ -54,7 +65,6 @@ public final class WallpaperPickerSections implements CustomizationSections { FragmentActivity activity, LifecycleOwner lifecycleOwner, WallpaperColorsViewModel wallpaperColorsViewModel, - WorkspaceViewModel workspaceViewModel, PermissionRequester permissionRequester, WallpaperPreviewNavigator wallpaperPreviewNavigator, CustomizationSectionNavigationController sectionNavigationController, @@ -62,10 +72,17 @@ public final class WallpaperPickerSections implements CustomizationSections { DisplayUtils displayUtils) { List<CustomizationSectionController<?>> sectionControllers = new ArrayList<>(); - sectionControllers.add(new WallpaperSectionController( - activity, lifecycleOwner, permissionRequester, wallpaperColorsViewModel, - workspaceViewModel, sectionNavigationController, wallpaperPreviewNavigator, - savedInstanceState, displayUtils)); + sectionControllers.add( + new WallpaperSectionController( + activity, + lifecycleOwner, + permissionRequester, + wallpaperColorsViewModel, + null, + sectionNavigationController, + wallpaperPreviewNavigator, + savedInstanceState, + displayUtils)); return sectionControllers; } diff --git a/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java b/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java index 4b0e5da2..12929bcc 100755 --- a/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java +++ b/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java @@ -73,9 +73,10 @@ public class WallpaperPreferenceKeys { "num_days_daily_rotation_failed"; String KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED = "num_days_daily_rotation_not_attempted"; - String KEY_HOME_WALLPAPER_PACKAGE_NAME = "home_wallpaper_package_name"; String KEY_HOME_WALLPAPER_SERVICE_NAME = "home_wallpaper_service_name"; + String KEY_LOCK_WALLPAPER_SERVICE_NAME = "lock_wallpaper_service_name"; String KEY_PREVIEW_WALLPAPER_COLOR_ID = "preview_wallpaper_color_id"; - String KEY_WALLPAPER_EFFECTS = "wallpaper_effects"; + String KEY_HOME_WALLPAPER_EFFECTS = "home_wallpaper_effects"; + String KEY_LOCK_WALLPAPER_EFFECTS = "lock_wallpaper_effects"; } } diff --git a/src/com/android/wallpaper/module/WallpaperPreferences.java b/src/com/android/wallpaper/module/WallpaperPreferences.java index 184972b1..30bcd72b 100755 --- a/src/com/android/wallpaper/module/WallpaperPreferences.java +++ b/src/com/android/wallpaper/module/WallpaperPreferences.java @@ -17,6 +17,7 @@ package com.android.wallpaper.module; import android.annotation.TargetApi; import android.app.WallpaperColors; +import android.app.WallpaperManager.SetWallpaperFlags; import android.graphics.Bitmap; import android.os.Build; @@ -140,16 +141,6 @@ public interface WallpaperPreferences { void setHomeWallpaperHashCode(long hashCode); /** - * Gets the home wallpaper's package name, which is present for live wallpapers. - */ - String getHomeWallpaperPackageName(); - - /** - * Sets the home wallpaper's package name, which is present for live wallpapers. - */ - void setHomeWallpaperPackageName(String packageName); - - /** * Gets the home wallpaper's service name, which is present for live wallpapers. */ String getHomeWallpaperServiceName(); @@ -184,6 +175,18 @@ public interface WallpaperPreferences { void setHomeWallpaperRemoteId(String wallpaperRemoteId); /** + * Gets the home wallpaper's effects. + */ + String getHomeWallpaperEffects(); + + /** + * Sets the home wallpaper's effects to SharedPreferences. + * + * @param wallpaperEffects The wallpaper effects. + */ + void setHomeWallpaperEffects(String wallpaperEffects); + + /** * Returns the lock wallpaper's action URL or null if there is none. */ String getLockWallpaperActionUrl(); @@ -262,6 +265,16 @@ public interface WallpaperPreferences { void setLockWallpaperHashCode(long hashCode); /** + * Gets the lock wallpaper's service name, which is present for live wallpapers. + */ + String getLockWallpaperServiceName(); + + /** + * Sets the lock wallpaper's service name, which is present for live wallpapers. + */ + void setLockWallpaperServiceName(String serviceName); + + /** * Gets the lock wallpaper's ID, which is provided by WallpaperManager for static wallpapers. */ @TargetApi(Build.VERSION_CODES.N) @@ -286,6 +299,18 @@ public interface WallpaperPreferences { void setLockWallpaperRemoteId(String wallpaperRemoteId); /** + * Gets the lock wallpaper's effects. + */ + String getLockWallpaperEffects(); + + /** + * Sets the lock wallpaper's effects to SharedPreferences. + * + * @param wallpaperEffects The wallpaper effects. + */ + void setLockWallpaperEffects(String wallpaperEffects); + + /** * Persists the timestamp of a daily wallpaper rotation that just occurred. */ void addDailyRotation(long timestamp); @@ -505,18 +530,6 @@ public interface WallpaperPreferences { String wallpaperId); /** - * Gets the wallpaper's effects. - */ - String getWallpaperEffects(); - - /** - * Sets the wallpaper's effects to SharedPreferences. - * - * @param wallpaperEffects The wallpaper effects. - */ - void setWallpaperEffects(String wallpaperEffects); - - /** * The possible wallpaper presentation modes, i.e., either "static" or "rotating". */ @IntDef({ @@ -545,29 +558,33 @@ public interface WallpaperPreferences { /** * Stores the given live wallpaper in the recent wallpapers list + * @param which flag indicating the wallpaper destination * @param wallpaperId unique identifier for this wallpaper * @param wallpaper {@link LiveWallpaperInfo} for the applied wallpaper * @param colors WallpaperColors to be used as placeholder for quickswitching */ - default void storeLatestHomeWallpaper(String wallpaperId, + default void storeLatestWallpaper(@SetWallpaperFlags int which, String wallpaperId, @NonNull LiveWallpaperInfo wallpaper, WallpaperColors colors) { // Do nothing in the default case. } /** * Stores the given static wallpaper data in the recent wallpapers list. + * @param which flag indicating the wallpaper destination * @param wallpaperId unique identifier for this wallpaper * @param wallpaper {@link WallpaperInfo} for the applied wallpaper * @param croppedWallpaperBitmap wallpaper bitmap exactly as applied to WallaperManager * @param colors WallpaperColors to be used as placeholder for quickswitching */ - default void storeLatestHomeWallpaper(String wallpaperId, @NonNull WallpaperInfo wallpaper, + default void storeLatestWallpaper(@SetWallpaperFlags int which, String wallpaperId, + @NonNull WallpaperInfo wallpaper, @NonNull Bitmap croppedWallpaperBitmap, WallpaperColors colors) { // Do nothing in the default case. } /** * Stores the given static wallpaper data in the recent wallpapers list. + * @param which flag indicating the wallpaper destination * @param wallpaperId unique identifier for this wallpaper * @param attributions List of attribution items. * @param actionUrl The action or "explore" URL for the wallpaper. @@ -575,7 +592,9 @@ public interface WallpaperPreferences { * @param croppedWallpaperBitmap wallpaper bitmap exactly as applied to WallaperManager * @param colors {@link WallpaperColors} to be used as placeholder for quickswitching */ - default void storeLatestHomeWallpaper(String wallpaperId, List<String> attributions, + default void storeLatestWallpaper( + @SetWallpaperFlags int which, + String wallpaperId, List<String> attributions, String actionUrl, String collectionId, @NonNull Bitmap croppedWallpaperBitmap, WallpaperColors colors) { // Do nothing in the default case. diff --git a/src/com/android/wallpaper/module/WallpaperSetter.java b/src/com/android/wallpaper/module/WallpaperSetter.java index 6924a078..b52cfd90 100644 --- a/src/com/android/wallpaper/module/WallpaperSetter.java +++ b/src/com/android/wallpaper/module/WallpaperSetter.java @@ -172,10 +172,11 @@ public class WallpaperSetter { wallpaper, wallpaperAsset, cropRect, wallpaperScale, destination, new SetWallpaperCallback() { @Override - public void onSuccess(WallpaperInfo wallpaperInfo) { + public void onSuccess(WallpaperInfo wallpaperInfo, + @Destination int destination) { onWallpaperApplied(wallpaper, containerActivity); if (callback != null) { - callback.onSuccess(wallpaper); + callback.onSuccess(wallpaper, destination); } } @@ -197,21 +198,25 @@ public class WallpaperSetter { // wallpaper and restore after setting the wallpaper finishes. saveAndLockScreenOrientationIfNeeded(activity); - if (destination == WallpaperPersister.DEST_LOCK_SCREEN) { + WallpaperManager wallpaperManager = WallpaperManager.getInstance(activity); + if (destination == WallpaperPersister.DEST_LOCK_SCREEN + && !wallpaperManager.isLockscreenLiveWallpaperEnabled()) { throw new IllegalArgumentException( - "Live wallpaper cannot be applied on lock screen only"); + "Live wallpaper cannot be applied on lock screen only"); } - WallpaperManager wallpaperManager = WallpaperManager.getInstance(activity); + setWallpaperComponent(wallpaperManager, wallpaper, destination); wallpaperManager.setWallpaperOffsetSteps(0.5f /* xStep */, 0.0f /* yStep */); wallpaperManager.setWallpaperOffsets( activity.getWindow().getDecorView().getRootView().getWindowToken(), 0.5f /* xOffset */, 0.0f /* yOffset */); - mPreferences.storeLatestHomeWallpaper(wallpaper.getWallpaperId(), wallpaper, colors); + mPreferences.storeLatestWallpaper(WallpaperPersister.destinationToFlags(destination), + wallpaper.getWallpaperId(), wallpaper, colors); onWallpaperApplied(wallpaper, activity); if (callback != null) { - callback.onSuccess(wallpaper); + callback.onSuccess(wallpaper, destination); } + mWallpaperPersister.onLiveWallpaperSet(destination); } catch (RuntimeException | IOException e) { onWallpaperApplyError(e, activity); if (callback != null) { @@ -233,7 +238,8 @@ public class WallpaperSetter { wallpaperManager.setWallpaperComponent( wallpaper.getWallpaperComponent().getComponent()); } - if (destination == WallpaperPersister.DEST_BOTH) { + if (!wallpaperManager.isLockscreenLiveWallpaperEnabled() + && destination == WallpaperPersister.DEST_BOTH) { wallpaperManager.clear(FLAG_LOCK); } } @@ -257,14 +263,16 @@ public class WallpaperSetter { } WallpaperManager wallpaperManager = WallpaperManager.getInstance(context); setWallpaperComponent(wallpaperManager, wallpaper, destination); - mPreferences.storeLatestHomeWallpaper(wallpaper.getWallpaperId(), wallpaper, - colors != null ? colors : + mPreferences.storeLatestWallpaper(WallpaperPersister.destinationToFlags(destination), + 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); + callback.onSuccess(wallpaper, destination); } + mWallpaperPersister.onLiveWallpaperSet(destination); } catch (RuntimeException | IOException e) { // Not call onWallpaperApplyError() as no UI is presented. if (callback != null) { @@ -353,6 +361,15 @@ public class WallpaperSetter { } }; + WallpaperManager wallpaperManager = WallpaperManager.getInstance(activity); + SetWallpaperDialogFragment setWallpaperDialog = new SetWallpaperDialogFragment(); + setWallpaperDialog.setTitleResId(titleResId); + setWallpaperDialog.setListener(listenerWrapper); + if (wallpaperManager.isLockscreenLiveWallpaperEnabled()) { + setWallpaperDialog.show(fragmentManager, TAG_SET_WALLPAPER_DIALOG_FRAGMENT); + return; + } + WallpaperStatusChecker wallpaperStatusChecker = InjectorProvider.getInjector().getWallpaperStatusChecker(); boolean isLiveWallpaperSet = @@ -361,9 +378,6 @@ public class WallpaperSetter { boolean isBuiltIn = !isLiveWallpaperSet && !wallpaperStatusChecker.isHomeStaticWallpaperSet(activity); - SetWallpaperDialogFragment setWallpaperDialog = new SetWallpaperDialogFragment(); - setWallpaperDialog.setTitleResId(titleResId); - setWallpaperDialog.setListener(listenerWrapper); if ((isLiveWallpaperSet || isBuiltIn) && !wallpaperStatusChecker.isLockWallpaperSet(activity)) { if (isLiveWallpaper) { diff --git a/src/com/android/wallpaper/picker/CategorySelectorFragment.java b/src/com/android/wallpaper/picker/CategorySelectorFragment.java index 2b6c71dc..fe36592e 100644 --- a/src/com/android/wallpaper/picker/CategorySelectorFragment.java +++ b/src/com/android/wallpaper/picker/CategorySelectorFragment.java @@ -47,6 +47,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.wallpaper.R; import com.android.wallpaper.asset.Asset; +import com.android.wallpaper.effects.EffectsController; import com.android.wallpaper.model.Category; import com.android.wallpaper.model.CategoryProvider; import com.android.wallpaper.model.LiveWallpaperInfo; @@ -299,6 +300,11 @@ public class CategorySelectorFragment extends AppbarFragment { eventLogger.logCategorySelected(mCategory.getCollectionId()); if (mCategory.supportsCustomPhotos()) { + EffectsController effectsController = + InjectorProvider.getInjector().getEffectsController(getContext()); + if (!effectsController.isEffectTriggered()) { + effectsController.triggerEffect(getContext()); + } getCategorySelectorFragmentHost().requestCustomPhotoPicker( new MyPhotosStarter.PermissionChangedListener() { @Override diff --git a/src/com/android/wallpaper/picker/CustomizationPickerActivity.java b/src/com/android/wallpaper/picker/CustomizationPickerActivity.java index 2351c72e..3f8c2d03 100644 --- a/src/com/android/wallpaper/picker/CustomizationPickerActivity.java +++ b/src/com/android/wallpaper/picker/CustomizationPickerActivity.java @@ -52,7 +52,6 @@ import com.android.wallpaper.picker.AppbarFragment.AppbarFragmentHost; import com.android.wallpaper.picker.CategorySelectorFragment.CategorySelectorFragmentHost; import com.android.wallpaper.picker.MyPhotosStarter.PermissionChangedListener; import com.android.wallpaper.picker.individual.IndividualPickerFragment.IndividualPickerFragmentHost; -import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor; import com.android.wallpaper.util.ActivityUtils; import com.android.wallpaper.util.DeepLinkUtils; import com.android.wallpaper.util.LaunchUtils; @@ -79,7 +78,7 @@ public class CustomizationPickerActivity extends FragmentActivity implements App private BottomActionBar mBottomActionBar; private boolean mIsSafeToCommitFragmentTransaction; - @Nullable private UndoInteractor mUndoInteractor; + private boolean mIsUseRevampedUi; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -109,7 +108,9 @@ public class CustomizationPickerActivity extends FragmentActivity implements App // See go/pdr-edge-to-edge-guide. WindowCompat.setDecorFitsSystemWindows(getWindow(), isSUWMode(this)); - final boolean isUseRevampedUi = injector.getFlags().isUseRevampedUi(this); + mIsUseRevampedUi = injector.getFlags().isUseRevampedUiEnabled(this); + final boolean startFromLockScreen = getIntent() == null + || !ActivityUtils.isLaunchedFromLauncher(getIntent()); Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container); if (fragment == null) { @@ -122,17 +123,30 @@ public class CustomizationPickerActivity extends FragmentActivity implements App // Switch to the target fragment. switchFragment(isWallpaperOnlyMode(getIntent()) - ? new WallpaperOnlyFragment() - : CustomizationPickerFragment.newInstance(isUseRevampedUi)); + ? WallpaperOnlyFragment.newInstance(mIsUseRevampedUi) + : CustomizationPickerFragment.newInstance( + mIsUseRevampedUi, startFromLockScreen)); + + // Cache the categories, but only if we're not restoring state (b/276767415). + mDelegate.prefetchCategories(); } - if (isUseRevampedUi) { - mUndoInteractor = injector.getUndoInteractor(this); - mUndoInteractor.startSession(); + if (savedInstanceState == null) { + // We only want to start a new undo session if this activity is brand-new. A non-new + // activity will have a non-null savedInstanceState. + if (mIsUseRevampedUi) { + injector.getUndoInteractor(this).startSession(); + } } final Intent intent = getIntent(); final String navigationDestination = intent.getStringExtra(EXTRA_DESTINATION); + // Consume the destination and commit the intent back so the OS doesn't revert to the same + // destination when we change color or wallpaper (which causes the activity to be + // recreated). + intent.removeExtra(EXTRA_DESTINATION); + setIntent(intent); + final String deepLinkCollectionId = DeepLinkUtils.getCollectionId(intent); if (!TextUtils.isEmpty(navigationDestination)) { @@ -147,10 +161,9 @@ public class CustomizationPickerActivity extends FragmentActivity implements App // Wallpaper Collection deep link case switchFragmentWithBackStack(new CategorySelectorFragment()); switchFragmentWithBackStack(InjectorProvider.getInjector().getIndividualPickerFragment( - deepLinkCollectionId)); + this, deepLinkCollectionId)); intent.setData(null); } - mDelegate.prefetchCategories(); } @Override @@ -254,7 +267,7 @@ public class CustomizationPickerActivity extends FragmentActivity implements App return; } switchFragmentWithBackStack(InjectorProvider.getInjector().getIndividualPickerFragment( - category.getCollectionId())); + this, category.getCollectionId())); } @Override @@ -331,6 +344,15 @@ public class CustomizationPickerActivity extends FragmentActivity implements App if (mDelegate.handleActivityResult(requestCode, resultCode, data)) { if (isSUWMode(this)) { finishActivityForSUW(); + } else if (mIsUseRevampedUi) { + // We don't finish in the revamped UI to let the user have a chance to reset the + // change they made, should they want to. We do, however, remove all the fragments + // from our back stack to reveal the root fragment, revealing the main screen of the + // app. + final FragmentManager fragmentManager = getSupportFragmentManager(); + while (fragmentManager.getBackStackEntryCount() > 0) { + fragmentManager.popBackStackImmediate(); + } } else { finishActivityWithResultOk(); } diff --git a/src/com/android/wallpaper/picker/CustomizationPickerFragment.java b/src/com/android/wallpaper/picker/CustomizationPickerFragment.java index 380fe13c..cb0820d0 100644 --- a/src/com/android/wallpaper/picker/CustomizationPickerFragment.java +++ b/src/com/android/wallpaper/picker/CustomizationPickerFragment.java @@ -33,34 +33,40 @@ import com.android.wallpaper.R; import com.android.wallpaper.model.CustomizationSectionController; import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController; import com.android.wallpaper.model.PermissionRequester; -import com.android.wallpaper.model.WallpaperColorsViewModel; import com.android.wallpaper.model.WallpaperPreviewNavigator; -import com.android.wallpaper.model.WorkspaceViewModel; import com.android.wallpaper.module.CustomizationSections; import com.android.wallpaper.module.FragmentFactory; import com.android.wallpaper.module.Injector; import com.android.wallpaper.module.InjectorProvider; import com.android.wallpaper.picker.customization.ui.binder.CustomizationPickerBinder; import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationPickerViewModel; +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel; import com.android.wallpaper.util.ActivityUtils; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import kotlinx.coroutines.DisposableHandle; + /** The Fragment UI for customization sections. */ public class CustomizationPickerFragment extends AppbarFragment implements CustomizationSectionNavigationController { private static final String TAG = "CustomizationPickerFragment"; private static final String SCROLL_POSITION_Y = "SCROLL_POSITION_Y"; - private static final String KEY_IS_USE_REVAMPED_UI = "is_use_revamped_ui"; + protected static final String KEY_IS_USE_REVAMPED_UI = "is_use_revamped_ui"; + private static final String KEY_START_FROM_LOCK_SCREEN = "start_from_lock_screen"; + private DisposableHandle mBinding; /** Returns a new instance of {@link CustomizationPickerFragment}. */ - public static CustomizationPickerFragment newInstance(boolean isUseRevampedUi) { + public static CustomizationPickerFragment newInstance( + boolean isUseRevampedUi, + boolean startFromLockScreen) { final CustomizationPickerFragment fragment = new CustomizationPickerFragment(); final Bundle args = new Bundle(); args.putBoolean(KEY_IS_USE_REVAMPED_UI, isUseRevampedUi); + args.putBoolean(KEY_START_FROM_LOCK_SCREEN, startFromLockScreen); fragment.setArguments(args); return fragment; } @@ -68,9 +74,11 @@ public class CustomizationPickerFragment extends AppbarFragment implements // Note that the section views will be displayed by the list ordering. private final List<CustomizationSectionController<?>> mSectionControllers = new ArrayList<>(); private NestedScrollView mNestedScrollView; - @Nullable private Bundle mBackStackSavedInstanceState; + @Nullable + private Bundle mBackStackSavedInstanceState; private final FragmentFactory mFragmentFactory; - @Nullable private CustomizationPickerViewModel mViewModel; + @Nullable + private CustomizationPickerViewModel mViewModel; public CustomizationPickerFragment() { mFragmentFactory = InjectorProvider.getInjector().getFragmentFactory(); @@ -79,9 +87,11 @@ public class CustomizationPickerFragment extends AppbarFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.collapsing_toolbar_container_layout, - container, /* attachToRoot= */ false); - + final boolean shouldUseRevampedUi = shouldUseRevampedUi(); + final int layoutId = shouldUseRevampedUi + ? R.layout.toolbar_container_layout + : R.layout.collapsing_toolbar_container_layout; + final View view = inflater.inflate(layoutId, container, false); if (ActivityUtils.isLaunchedFromSettingsRelated(getActivity().getIntent())) { setUpToolbar(view, !ActivityEmbeddingUtils.shouldHideNavigateUpButton( getActivity(), /* isSecondLayerPage= */ true)); @@ -90,16 +100,7 @@ public class CustomizationPickerFragment extends AppbarFragment implements } final Injector injector = InjectorProvider.getInjector(); - final Bundle args = getArguments(); - final boolean isUseRevampedUi; - if (args != null && args.containsKey(KEY_IS_USE_REVAMPED_UI)) { - isUseRevampedUi = args.getBoolean(KEY_IS_USE_REVAMPED_UI); - } else { - throw new IllegalStateException( - "Must contain KEY_IS_USE_REVAMPED_UI argument, did you instantiate directly" - + " instead of using the newInstance function?"); - } - if (isUseRevampedUi) { + if (shouldUseRevampedUi) { setContentView(view, R.layout.fragment_tabbed_customization_picker); mViewModel = new ViewModelProvider( this, @@ -108,19 +109,26 @@ public class CustomizationPickerFragment extends AppbarFragment implements savedInstanceState, injector.getUndoInteractor(requireContext())) ).get(CustomizationPickerViewModel.class); + final Bundle arguments = getArguments(); + mViewModel.setInitialScreen( + arguments != null && arguments.getBoolean(KEY_START_FROM_LOCK_SCREEN)); setUpToolbarMenu(R.menu.undoable_customization_menu); final Bundle finalSavedInstanceState = savedInstanceState; - CustomizationPickerBinder.bind( + if (mBinding != null) { + mBinding.dispose(); + } + mBinding = CustomizationPickerBinder.bind( view, getToolbarId(), mViewModel, this, - isOnLockScreen -> getSectionControllers( - isOnLockScreen - ? CustomizationSections.Screen.LOCK_SCREEN - : CustomizationSections.Screen.HOME_SCREEN, - finalSavedInstanceState)); + isOnLockScreen -> filterAvailableSections( + getSectionControllers( + isOnLockScreen + ? CustomizationSections.Screen.LOCK_SCREEN + : CustomizationSections.Screen.HOME_SCREEN, + finalSavedInstanceState))); } else { setContentView(view, R.layout.fragment_customization_picker); } @@ -132,7 +140,7 @@ public class CustomizationPickerFragment extends AppbarFragment implements mNestedScrollView = view.findViewById(R.id.scroll_container); - if (!isUseRevampedUi) { + if (!shouldUseRevampedUi) { ViewGroup sectionContainer = view.findViewById(R.id.section_container); sectionContainer.setOnApplyWindowInsetsListener((v, windowInsets) -> { v.setPadding( @@ -187,12 +195,12 @@ public class CustomizationPickerFragment extends AppbarFragment implements @Override protected int getToolbarId() { - return R.id.action_bar; + return shouldUseRevampedUi() ? R.id.toolbar : R.id.action_bar; } @Override protected int getToolbarColorId() { - return android.R.color.transparent; + return shouldUseRevampedUi() ? R.color.toolbar_color : android.R.color.transparent; } @Override @@ -257,14 +265,10 @@ public class CustomizationPickerFragment extends AppbarFragment implements mSectionControllers.clear(); mSectionControllers.addAll( - getAvailableSections(getAvailableSectionControllers(savedInstanceState))); - } - - private List<CustomizationSectionController<?>> getAvailableSectionControllers( - @Nullable Bundle savedInstanceState) { - return getSectionControllers( - null, - savedInstanceState); + filterAvailableSections( + getSectionControllers( + null, + savedInstanceState))); } private List<CustomizationSectionController<?>> getSectionControllers( @@ -272,50 +276,55 @@ public class CustomizationPickerFragment extends AppbarFragment implements @Nullable Bundle savedInstanceState) { final Injector injector = InjectorProvider.getInjector(); - WallpaperColorsViewModel wcViewModel = new ViewModelProvider(getActivity()) - .get(WallpaperColorsViewModel.class); - WorkspaceViewModel workspaceViewModel = new ViewModelProvider(getActivity()) - .get(WorkspaceViewModel.class); + WallpaperQuickSwitchViewModel wallpaperQuickSwitchViewModel = new ViewModelProvider( + getActivity(), + WallpaperQuickSwitchViewModel.newFactory( + this, + savedInstanceState, + injector.getWallpaperInteractor(requireContext()))) + .get(WallpaperQuickSwitchViewModel.class); CustomizationSections sections = injector.getCustomizationSections(getActivity()); if (screen == null) { return sections.getAllSectionControllers( getActivity(), getViewLifecycleOwner(), - wcViewModel, - workspaceViewModel, + injector.getWallpaperColorsViewModel(), getPermissionRequester(), getWallpaperPreviewNavigator(), this, savedInstanceState, injector.getDisplayUtils(getActivity())); } else { - return sections.getSectionControllersForScreen( + return sections.getRevampedUISectionControllersForScreen( screen, getActivity(), getViewLifecycleOwner(), - wcViewModel, - workspaceViewModel, + injector.getWallpaperColorsViewModel(), getPermissionRequester(), getWallpaperPreviewNavigator(), this, savedInstanceState, injector.getCurrentWallpaperInfoFactory(requireContext()), - injector.getDisplayUtils(getActivity())); + injector.getDisplayUtils(getActivity()), + wallpaperQuickSwitchViewModel, + injector.getWallpaperInteractor(requireContext())); } } - protected List<CustomizationSectionController<?>> getAvailableSections( + /** Returns a filtered list containing only the available section controllers. */ + protected List<CustomizationSectionController<?>> filterAvailableSections( List<CustomizationSectionController<?>> controllers) { return controllers.stream() .filter(controller -> { - if(controller.isAvailable(getContext())) { + if (controller.isAvailable(getContext())) { return true; } else { controller.release(); Log.d(TAG, "Section is not available: " + controller); return false; - }}) + } + }) .collect(Collectors.toList()); } @@ -326,4 +335,15 @@ public class CustomizationPickerFragment extends AppbarFragment implements private WallpaperPreviewNavigator getWallpaperPreviewNavigator() { return (WallpaperPreviewNavigator) getActivity(); } + + private boolean shouldUseRevampedUi() { + final Bundle args = getArguments(); + if (args != null && args.containsKey(KEY_IS_USE_REVAMPED_UI)) { + return args.getBoolean(KEY_IS_USE_REVAMPED_UI); + } else { + throw new IllegalStateException( + "Must contain KEY_IS_USE_REVAMPED_UI argument, did you instantiate directly" + + " instead of using the newInstance function?"); + } + } } diff --git a/src/com/android/wallpaper/picker/DisplayAspectRatioLinearLayout.kt b/src/com/android/wallpaper/picker/DisplayAspectRatioLinearLayout.kt new file mode 100644 index 00000000..f970a9b9 --- /dev/null +++ b/src/com/android/wallpaper/picker/DisplayAspectRatioLinearLayout.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 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.widget.LinearLayout +import androidx.core.view.children +import androidx.core.view.updateLayoutParams +import com.android.wallpaper.util.ScreenSizeCalculator + +/** + * [LinearLayout] that sizes its children using a fixed aspect ratio that is the same as that of the + * display, and can lay out multiple children horizontally with margin + */ +class DisplayAspectRatioLinearLayout( + context: Context, + attrs: AttributeSet?, +) : LinearLayout(context, attrs) { + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + + val screenAspectRatio = ScreenSizeCalculator.getInstance().getScreenAspectRatio(context) + val parentWidth = this.measuredWidth + val parentHeight = this.measuredHeight + val itemSpacingPx = ITEM_SPACING_DP.toPx(context.resources.displayMetrics.density) + val (childWidth, childHeight) = + if (orientation == HORIZONTAL) { + val availableWidth = + parentWidth - paddingStart - paddingEnd - (childCount - 1) * itemSpacingPx + val availableHeight = parentHeight - paddingTop - paddingBottom + var width = availableWidth / childCount + var height = (width * screenAspectRatio).toInt() + if (height > availableHeight) { + height = availableHeight + width = (height / screenAspectRatio).toInt() + } + width to height + } else { + val availableWidth = parentWidth - paddingStart - paddingEnd + val availableHeight = + parentHeight - paddingTop - paddingBottom - (childCount - 1) * itemSpacingPx + var height = availableHeight / childCount + var width = (height / screenAspectRatio).toInt() + if (width > availableWidth) { + width = availableWidth + height = (width * screenAspectRatio).toInt() + } + width to height + } + + val itemSpacingHalfPx = ITEM_SPACING_DP_HALF.toPx(context.resources.displayMetrics.density) + children.forEachIndexed { index, child -> + val addSpacingToStart = index > 0 + val addSpacingToEnd = index < (childCount - 1) + if (orientation == HORIZONTAL) { + child.updateLayoutParams<MarginLayoutParams> { + if (addSpacingToStart) this.marginStart = itemSpacingHalfPx + if (addSpacingToEnd) this.marginEnd = itemSpacingHalfPx + } + } else { + child.updateLayoutParams<MarginLayoutParams> { + if (addSpacingToStart) this.topMargin = itemSpacingHalfPx + if (addSpacingToEnd) this.bottomMargin = itemSpacingHalfPx + } + } + + child.measure( + MeasureSpec.makeMeasureSpec( + childWidth, + MeasureSpec.EXACTLY, + ), + MeasureSpec.makeMeasureSpec( + childHeight, + MeasureSpec.EXACTLY, + ), + ) + } + } + + private fun Int.toPx(density: Float): Int { + return (this * density).toInt() + } + + companion object { + private const val ITEM_SPACING_DP = 12 + private const val ITEM_SPACING_DP_HALF = ITEM_SPACING_DP / 2 + } +} diff --git a/src/com/android/wallpaper/picker/FullPreviewActivity.java b/src/com/android/wallpaper/picker/FullPreviewActivity.java index ce780644..5a22b62c 100755 --- a/src/com/android/wallpaper/picker/FullPreviewActivity.java +++ b/src/com/android/wallpaper/picker/FullPreviewActivity.java @@ -17,20 +17,21 @@ package com.android.wallpaper.picker; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.os.Bundle; import android.transition.Slide; -import android.view.View; import android.view.Window; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import com.android.wallpaper.R; -import com.android.wallpaper.model.InlinePreviewIntentFactory; +import com.android.wallpaper.config.BaseFlags; import com.android.wallpaper.model.WallpaperInfo; import com.android.wallpaper.module.InjectorProvider; import com.android.wallpaper.picker.AppbarFragment.AppbarFragmentHost; import com.android.wallpaper.util.ActivityUtils; +import com.android.wallpaper.util.DisplayUtils; /** * Activity that displays a full preview of a specific wallpaper and provides the ability to set the @@ -43,7 +44,7 @@ public class FullPreviewActivity extends BasePreviewActivity implements AppbarFr */ public static Intent newIntent(Context packageContext, WallpaperInfo wallpaperInfo) { Intent intent = new Intent(packageContext, FullPreviewActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.putExtra(EXTRA_WALLPAPER_INFO, wallpaperInfo); return intent; } @@ -74,7 +75,9 @@ public class FullPreviewActivity extends BasePreviewActivity implements AppbarFr if (fragment == null) { Intent intent = getIntent(); WallpaperInfo wallpaper = intent.getParcelableExtra(EXTRA_WALLPAPER_INFO); - boolean viewAsHome = intent.getBooleanExtra(EXTRA_VIEW_AS_HOME, true); + BaseFlags flags = InjectorProvider.getInjector().getFlags(); + boolean viewAsHome = intent.getBooleanExtra(EXTRA_VIEW_AS_HOME, !flags + .isFullscreenWallpaperPreviewEnabled(this)); boolean testingModeEnabled = intent.getBooleanExtra(EXTRA_TESTING_MODE_ENABLED, false); fragment = InjectorProvider.getInjector().getPreviewFragment( /* context= */ this, @@ -99,26 +102,15 @@ public class FullPreviewActivity extends BasePreviewActivity implements AppbarFr return !ActivityUtils.isSUWMode(getBaseContext()); } - /** - * Implementation that provides an intent to start a PreviewActivity. - */ - public static class PreviewActivityIntentFactory implements InlinePreviewIntentFactory { - @Override - public Intent newIntent(Context context, WallpaperInfo wallpaper) { - return FullPreviewActivity.newIntent(context, wallpaper); - } - } - @Override protected void onResume() { super.onResume(); + DisplayUtils displayUtils = InjectorProvider.getInjector().getDisplayUtils(this); + int orientation = displayUtils.isOnWallpaperDisplay(this) + ? ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + setRequestedOrientation(orientation); if (isInMultiWindowMode()) { onBackPressed(); } - // Hide the navigation bar - View decorView = getWindow().getDecorView(); - int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN; - decorView.setSystemUiVisibility(uiOptions); } } diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java index 6d75c87b..ba477b7d 100755 --- a/src/com/android/wallpaper/picker/ImagePreviewFragment.java +++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java @@ -424,7 +424,7 @@ public class ImagePreviewFragment extends PreviewFragment { BitmapCropper bitmapCropper = mInjector.getBitmapCropper(); bitmapCropper.cropAndScaleBitmap(mWallpaperAsset, mFullResImageView.getScale(), - calculateCropRect(context), /* adjustForRtl= */ false, + calculateCropRect(context, /* cropExtraWidth= */ true), /* adjustForRtl= */ false, new BitmapCropper.Callback() { @Override public void onBitmapCropped(Bitmap croppedBitmap) { @@ -546,7 +546,7 @@ public class ImagePreviewFragment extends PreviewFragment { mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition); } - private Rect calculateCropRect(Context context) { + private Rect calculateCropRect(Context context, boolean cropExtraWidth) { float wallpaperZoom = mFullResImageView.getScale(); Context appContext = context.getApplicationContext(); @@ -563,12 +563,13 @@ public class ImagePreviewFragment extends PreviewFragment { Point cropSurfaceSize = WallpaperCropUtils.calculateCropSurfaceSize(res, maxCrop, minCrop, cropWidth, cropHeight); return WallpaperCropUtils.calculateCropRect(appContext, hostViewSize, - cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom); + cropSurfaceSize, mRawWallpaperSize, visibleFileRect, wallpaperZoom, cropExtraWidth); } @Override protected void setCurrentWallpaper(@Destination int destination) { - Rect cropRect = calculateCropRect(getContext()); + // Only crop extra wallpaper width for single display devices. + Rect cropRect = calculateCropRect(getContext(), !mDisplayUtils.hasMultiInternalDisplays()); float screenScale = WallpaperCropUtils.getScaleOfScreenResolution( mFullResImageView.getScale(), cropRect, mWallpaperScreenSize.x, mWallpaperScreenSize.y); diff --git a/src/com/android/wallpaper/picker/PreviewActivity.java b/src/com/android/wallpaper/picker/PreviewActivity.java index ba39ba4e..e7646250 100755 --- a/src/com/android/wallpaper/picker/PreviewActivity.java +++ b/src/com/android/wallpaper/picker/PreviewActivity.java @@ -25,10 +25,12 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import com.android.wallpaper.R; +import com.android.wallpaper.config.BaseFlags; import com.android.wallpaper.model.ImageWallpaperInfo; import com.android.wallpaper.model.InlinePreviewIntentFactory; import com.android.wallpaper.model.WallpaperInfo; import com.android.wallpaper.module.InjectorProvider; +import com.android.wallpaper.module.LargeScreenMultiPanesChecker; import com.android.wallpaper.picker.AppbarFragment.AppbarFragmentHost; import com.android.wallpaper.util.ActivityUtils; @@ -61,7 +63,9 @@ public class PreviewActivity extends BasePreviewActivity implements AppbarFragme if (fragment == null) { Intent intent = getIntent(); WallpaperInfo wallpaper = intent.getParcelableExtra(EXTRA_WALLPAPER_INFO); - boolean viewAsHome = intent.getBooleanExtra(EXTRA_VIEW_AS_HOME, true); + BaseFlags flags = InjectorProvider.getInjector().getFlags(); + boolean viewAsHome = intent.getBooleanExtra(EXTRA_VIEW_AS_HOME, !flags + .isFullscreenWallpaperPreviewEnabled(this)); boolean testingModeEnabled = intent.getBooleanExtra(EXTRA_TESTING_MODE_ENABLED, false); fragment = InjectorProvider.getInjector().getPreviewFragment( /* context */ this, @@ -115,6 +119,14 @@ public class PreviewActivity extends BasePreviewActivity implements AppbarFragme public static class PreviewActivityIntentFactory implements InlinePreviewIntentFactory { @Override public Intent newIntent(Context context, WallpaperInfo wallpaper) { + LargeScreenMultiPanesChecker multiPanesChecker = new LargeScreenMultiPanesChecker(); + // Launch a full preview activity for devices supporting multipanel mode + if (multiPanesChecker.isMultiPanesEnabled(context) + && InjectorProvider.getInjector().getFlags() + .isFullscreenWallpaperPreviewEnabled(context)) { + return FullPreviewActivity.newIntent(context, wallpaper); + } + return PreviewActivity.newIntent(context, wallpaper); } } diff --git a/src/com/android/wallpaper/picker/PreviewFragment.java b/src/com/android/wallpaper/picker/PreviewFragment.java index e9e78c8a..6671b208 100755 --- a/src/com/android/wallpaper/picker/PreviewFragment.java +++ b/src/com/android/wallpaper/picker/PreviewFragment.java @@ -203,7 +203,7 @@ public abstract class PreviewFragment extends AppbarFragment implements mFullScreenAnimation.getStatusBarHeight(), previewHeader.getPaddingRight(), previewHeader.getPaddingBottom()); - return windowInsets.consumeSystemWindowInsets(); + return windowInsets.CONSUMED; } ); diff --git a/src/com/android/wallpaper/picker/StandalonePreviewActivity.java b/src/com/android/wallpaper/picker/StandalonePreviewActivity.java index f4938059..3b65306c 100755 --- a/src/com/android/wallpaper/picker/StandalonePreviewActivity.java +++ b/src/com/android/wallpaper/picker/StandalonePreviewActivity.java @@ -19,12 +19,13 @@ import static com.android.wallpaper.util.ActivityUtils.startActivityForResultSaf import android.Manifest.permission; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.util.Log; -import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; @@ -62,7 +63,8 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap enableFullScreen(); - mUserEventLogger = InjectorProvider.getInjector().getUserEventLogger(getApplicationContext()); + mUserEventLogger = InjectorProvider.getInjector().getUserEventLogger( + getApplicationContext()); mUserEventLogger.logStandalonePreviewLaunched(); Intent cropAndSetWallpaperIntent = getIntent(); @@ -80,10 +82,11 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap mUserEventLogger.logStandalonePreviewImageUriHasReadPermission( isReadPermissionGrantedForImageUri); - // Request storage permission if necessary (i.e., on Android M and later if storage permission - // has not already been granted) and delay loading the PreviewFragment until the permission is - // granted. - if (!isReadPermissionGrantedForImageUri && !isReadExternalStoragePermissionGrantedForApp()) { + // Request storage permission if necessary (i.e., on Android M and later if storage + // permission has not already been granted) and delay loading the PreviewFragment until the + // permission is granted. + if (!isReadPermissionGrantedForImageUri + && !isReadExternalStoragePermissionGrantedForApp()) { requestPermissions( new String[]{permission.READ_MEDIA_IMAGES}, READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE); @@ -103,8 +106,20 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap } @Override + protected void onResume() { + super.onResume(); + Resources res = getResources(); + boolean isDeviceFoldableOrTablet = res.getBoolean(R.bool.is_large_screen); + + if (!isDeviceFoldableOrTablet) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + + @SuppressWarnings("MissingSuperCall") // TODO: Fix me + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { + @NonNull int[] grantResults) { // Load the preview fragment if the storage permission was granted. if (requestCode == READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE) { boolean isGranted = permissions.length > 0 @@ -137,14 +152,6 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap return getIntent().getBooleanExtra(KEY_UP_ARROW, false); } - @Override - protected void enableFullScreen() { - super.enableFullScreen(); - getWindow().setFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - } - /** * Launches multi-pane when it is enabled, for non-Settings' trampoline launch case will * retrieve EXTRA_STREAM's image URI and assign back its intent by calling setData(). @@ -155,22 +162,10 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap Intent intent = getIntent(); if (!ActivityUtils.isLaunchedFromSettingsTrampoline(intent) && !ActivityUtils.isLaunchedFromSettingsRelated(intent)) { - Uri uri = intent.getData(); - if (uri != null) { - // Grant URI permission for next launching activity. - grantUriPermission(getPackageName(), uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION); + if (!InjectorProvider.getInjector().getFlags().isFullscreenWallpaperPreviewEnabled( + this)) { + launchMultiPanes(checker); } - - Intent previewLaunch = checker.getMultiPanesIntent(intent); - previewLaunch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - // Put image URI and back arrow condition to separate extras. - .putExtra(Intent.EXTRA_STREAM, intent.getData()) - .putExtra(KEY_UP_ARROW, true); - - startActivityForResultSafely(/* activity= */ this, previewLaunch, /* requestCode= */ - 0); - finish(); } else { Uri uri = intent.hasExtra(Intent.EXTRA_STREAM) ? intent.getParcelableExtra( Intent.EXTRA_STREAM) : null; @@ -181,6 +176,26 @@ public class StandalonePreviewActivity extends BasePreviewActivity implements Ap } } + private void launchMultiPanes(MultiPanesChecker checker) { + Intent intent = getIntent(); + Uri uri = intent.getData(); + if (uri != null) { + // Grant URI permission for next launching activity. + grantUriPermission(getPackageName(), uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + Intent previewLaunch = checker.getMultiPanesIntent(intent); + previewLaunch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + // Put image URI and back arrow condition to separate extras. + .putExtra(Intent.EXTRA_STREAM, intent.getData()) + .putExtra(KEY_UP_ARROW, true); + + startActivityForResultSafely(/* activity= */ this, previewLaunch, /* requestCode= */ + 0); + finish(); + } + /** * Creates a new instance of {@link PreviewFragment} and loads the fragment into this activity's * fragment container so that it's shown to the user. diff --git a/src/com/android/wallpaper/picker/TouchForwardingLayout.java b/src/com/android/wallpaper/picker/TouchForwardingLayout.java index 2cb692de..ced59689 100644 --- a/src/com/android/wallpaper/picker/TouchForwardingLayout.java +++ b/src/com/android/wallpaper/picker/TouchForwardingLayout.java @@ -17,6 +17,7 @@ package com.android.wallpaper.picker; import android.content.Context; import android.util.AttributeSet; +import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -26,13 +27,22 @@ public class TouchForwardingLayout extends FrameLayout { private View mView; private boolean mForwardingEnabled; + private GestureDetector mGestureDetector; public TouchForwardingLayout(Context context, AttributeSet attrs) { super(context, attrs); + mGestureDetector = new GestureDetector(context, + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + return performClick(); + } + }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { + mGestureDetector.onTouchEvent(ev); if (mView != null && mForwardingEnabled) { mView.dispatchTouchEvent(ev); } diff --git a/src/com/android/wallpaper/picker/ViewOnlyPreviewActivity.java b/src/com/android/wallpaper/picker/ViewOnlyPreviewActivity.java index 4ff3c2ea..7377103f 100755 --- a/src/com/android/wallpaper/picker/ViewOnlyPreviewActivity.java +++ b/src/com/android/wallpaper/picker/ViewOnlyPreviewActivity.java @@ -26,6 +26,7 @@ import com.android.wallpaper.R; import com.android.wallpaper.model.InlinePreviewIntentFactory; import com.android.wallpaper.model.WallpaperInfo; import com.android.wallpaper.module.InjectorProvider; +import com.android.wallpaper.module.LargeScreenMultiPanesChecker; import com.android.wallpaper.picker.AppbarFragment.AppbarFragmentHost; import com.android.wallpaper.util.ActivityUtils; @@ -94,6 +95,14 @@ public class ViewOnlyPreviewActivity extends BasePreviewActivity implements Appb @Override public Intent newIntent(Context context, WallpaperInfo wallpaper) { + LargeScreenMultiPanesChecker multiPanesChecker = new LargeScreenMultiPanesChecker(); + // Launch a full preview activity for devices supporting multipanel mode + if (multiPanesChecker.isMultiPanesEnabled(context) + && InjectorProvider.getInjector().getFlags() + .isFullscreenWallpaperPreviewEnabled(context)) { + return FullPreviewActivity.newIntent(context, wallpaper, mIsViewAsHome); + } + if (mIsHomeAndLockPreviews) { return ViewOnlyPreviewActivity.newIntent(context, wallpaper, mIsViewAsHome); } diff --git a/src/com/android/wallpaper/picker/WallpaperOnlyFragment.java b/src/com/android/wallpaper/picker/WallpaperOnlyFragment.java index 7673df2f..6d99bed9 100644 --- a/src/com/android/wallpaper/picker/WallpaperOnlyFragment.java +++ b/src/com/android/wallpaper/picker/WallpaperOnlyFragment.java @@ -15,6 +15,8 @@ */ package com.android.wallpaper.picker; +import android.os.Bundle; + import com.android.wallpaper.R; import com.android.wallpaper.model.CustomizationSectionController; import com.android.wallpaper.model.WallpaperSectionController; @@ -25,17 +27,26 @@ import java.util.stream.Collectors; /** The Fragment UI for wallpaper only section. */ public class WallpaperOnlyFragment extends CustomizationPickerFragment { + /** Returns a new instance of {@link WallpaperOnlyFragment}. */ + public static WallpaperOnlyFragment newInstance(boolean isUseRevampedUi) { + final WallpaperOnlyFragment fragment = new WallpaperOnlyFragment(); + final Bundle args = new Bundle(); + args.putBoolean(KEY_IS_USE_REVAMPED_UI, isUseRevampedUi); + fragment.setArguments(args); + return fragment; + } + @Override public CharSequence getDefaultTitle() { return getString(R.string.wallpaper_app_name); } @Override - protected List<CustomizationSectionController<?>> getAvailableSections( + protected List<CustomizationSectionController<?>> filterAvailableSections( List<CustomizationSectionController<?>> controllers) { List<CustomizationSectionController<?>> wallpaperOnlySections = controllers.stream() .filter(controller -> controller instanceof WallpaperSectionController) .collect(Collectors.toList()); - return super.getAvailableSections(wallpaperOnlySections); + return super.filterAvailableSections(wallpaperOnlySections); } } diff --git a/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java b/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java index 5b60c064..3c788ef4 100644 --- a/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java +++ b/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java @@ -467,7 +467,6 @@ public class WallpaperPickerDelegate implements MyPhotosStarter { PREVIEW_WALLPAPER_REQUEST_CODE); return false; case PREVIEW_LIVE_WALLPAPER_REQUEST_CODE: - mWallpaperPersister.onLiveWallpaperSet(); populateCategories(/* forceRefresh= */ true); return true; case VIEW_ONLY_PREVIEW_WALLPAPER_REQUEST_CODE: @@ -475,7 +474,6 @@ public class WallpaperPickerDelegate implements MyPhotosStarter { case PREVIEW_WALLPAPER_REQUEST_CODE: // User previewed and selected a wallpaper, so finish this activity. if (data != null && data.getBooleanExtra(IS_LIVE_WALLPAPER, false)) { - mWallpaperPersister.onLiveWallpaperSet(); populateCategories(/* forceRefresh= */ true); } return true; diff --git a/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java b/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java index bb4c0d36..9c26cc3d 100644 --- a/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java +++ b/src/com/android/wallpaper/picker/WorkspaceSurfaceHolderCallback.java @@ -46,12 +46,15 @@ public class WorkspaceSurfaceHolderCallback implements SurfaceHolder.Callback { private static final String TAG = "WsSurfaceHolderCallback"; private static final String KEY_WALLPAPER_COLORS = "wallpaper_colors"; + public static final int MESSAGE_ID_UPDATE_PREVIEW = 1337; + public static final String KEY_HIDE_BOTTOM_ROW = "hide_bottom_row"; private final SurfaceView mWorkspaceSurface; private final PreviewUtils mPreviewUtils; private final boolean mShouldUseWallpaperColors; private final AtomicBoolean mRequestPending = new AtomicBoolean(false); private WallpaperColors mWallpaperColors; + private boolean mHideBottomRow; private boolean mIsWallpaperColorsReady; private Surface mLastSurface; private Message mCallback; @@ -126,27 +129,45 @@ public class WorkspaceSurfaceHolderCallback implements SurfaceHolder.Callback { } mWallpaperColors = colors; mIsWallpaperColorsReady = true; - maybeRenderPreview(); + } + + /** + * Set the current flag if we should hide the workspace bottom row. + */ + public void setHideBottomRow(boolean hideBottomRow) { + mHideBottomRow = hideBottomRow; + } + + /** + * Hides the components in the bottom row. + * + * @param hide True to hide and false to show. + */ + public void hideBottomRow(boolean hide) { + Bundle data = new Bundle(); + data.putBoolean(KEY_HIDE_BOTTOM_ROW, hide); + send(MESSAGE_ID_UPDATE_PREVIEW, data); } public void setListener(WorkspaceRenderListener listener) { mListener = listener; } - private void maybeRenderPreview() { + /** + * Render the preview with the current selected {@link #mWallpaperColors} and + * {@link #mHideBottomRow}. + */ + public void maybeRenderPreview() { if ((mShouldUseWallpaperColors && !mIsWallpaperColorsReady) || mLastSurface == null) { return; } - mRequestPending.set(true); requestPreview(mWorkspaceSurface, (result) -> { mRequestPending.set(false); if (result != null && mLastSurface != null) { mWorkspaceSurface.setChildSurfacePackage( SurfaceViewUtils.getSurfacePackage(result)); - mCallback = SurfaceViewUtils.getCallback(result); - if (mNeedsToCleanUp) { cleanUp(); } else if (mListener != null) { @@ -216,6 +237,7 @@ public class WorkspaceSurfaceHolderCallback implements SurfaceHolder.Callback { Bundle request = SurfaceViewUtils.createSurfaceViewRequest(workspaceSurface, mExtras); if (mWallpaperColors != null) { request.putParcelable(KEY_WALLPAPER_COLORS, mWallpaperColors); + request.putBoolean(KEY_HIDE_BOTTOM_ROW, mHideBottomRow); } mPreviewUtils.renderPreview(request, callback); } diff --git a/src/com/android/wallpaper/picker/common/button/ui/viewbinder/ButtonViewBinder.kt b/src/com/android/wallpaper/picker/common/button/ui/viewbinder/ButtonViewBinder.kt new file mode 100644 index 00000000..6e63835b --- /dev/null +++ b/src/com/android/wallpaper/picker/common/button/ui/viewbinder/ButtonViewBinder.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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.common.button.ui.viewbinder + +import android.view.ContextThemeWrapper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.annotation.LayoutRes +import com.android.wallpaper.R +import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonViewModel +import com.android.wallpaper.picker.common.text.ui.viewbinder.TextViewBinder + +object ButtonViewBinder { + /** Returns a newly-created [View] that's already bound to the given [ButtonViewModel]. */ + fun create( + parent: ViewGroup, + viewModel: ButtonViewModel, + @LayoutRes buttonLayoutResourceId: Int = R.layout.dialog_button, + ): View { + val view = + LayoutInflater.from( + ContextThemeWrapper( + parent.context, + viewModel.style.styleResourceId, + ) + ) + .inflate( + buttonLayoutResourceId, + parent, + false, + ) + val text: TextView = view.requireViewById(R.id.text) + view.setOnClickListener { viewModel.onClicked?.invoke() } + + TextViewBinder.bind( + view = text, + viewModel = viewModel.text, + ) + + return view + } +} diff --git a/src/com/android/wallpaper/model/WorkspaceViewModel.kt b/src/com/android/wallpaper/picker/common/button/ui/viewmodel/ButtonStyle.kt index 627406ee..a83a8ab4 100644 --- a/src/com/android/wallpaper/model/WorkspaceViewModel.kt +++ b/src/com/android/wallpaper/picker/common/button/ui/viewmodel/ButtonStyle.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2023 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. @@ -12,18 +12,23 @@ * 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.model -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +package com.android.wallpaper.picker.common.button.ui.viewmodel -/** ViewModel class to keep track of workspace updates. */ -class WorkspaceViewModel : ViewModel() { +import androidx.annotation.StyleRes +import com.android.wallpaper.R - /** - * Triggers workspace updates through flipping the value from {@code false} to {@code true}, or - * from {@code true} to {@code false}. - */ - val updateWorkspace: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() } +sealed class ButtonStyle( + @StyleRes open val styleResourceId: Int, +) { + object Primary : + ButtonStyle( + styleResourceId = R.style.DialogButton_Primary, + ) + object Secondary : + ButtonStyle( + styleResourceId = R.style.DialogButton_Secondary, + ) } diff --git a/src/com/android/wallpaper/picker/common/button/ui/viewmodel/ButtonViewModel.kt b/src/com/android/wallpaper/picker/common/button/ui/viewmodel/ButtonViewModel.kt new file mode 100644 index 00000000..62f3e81d --- /dev/null +++ b/src/com/android/wallpaper/picker/common/button/ui/viewmodel/ButtonViewModel.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 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.common.button.ui.viewmodel + +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +data class ButtonViewModel( + val text: Text, + val style: ButtonStyle, + val onClicked: (() -> Unit)? = null, +) diff --git a/src/com/android/wallpaper/picker/common/dialog/ui/viewbinder/DialogViewBinder.kt b/src/com/android/wallpaper/picker/common/dialog/ui/viewbinder/DialogViewBinder.kt new file mode 100644 index 00000000..7130f21a --- /dev/null +++ b/src/com/android/wallpaper/picker/common/dialog/ui/viewbinder/DialogViewBinder.kt @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2023 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.common.dialog.ui.viewbinder + +import android.app.Dialog +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.LayoutRes +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible +import com.android.wallpaper.R +import com.android.wallpaper.picker.common.button.ui.viewbinder.ButtonViewBinder +import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel +import com.android.wallpaper.picker.common.icon.ui.viewbinder.IconViewBinder +import com.android.wallpaper.picker.common.text.ui.viewbinder.TextViewBinder + +object DialogViewBinder { + /** Returns a shown dialog that's bound to the given [DialogViewModel]. */ + fun show( + context: Context, + viewModel: DialogViewModel, + onDismissed: (() -> Unit)? = null, + @LayoutRes dialogLayoutResourceId: Int = R.layout.dialog_view, + @LayoutRes buttonLayoutResourceId: Int = R.layout.dialog_button, + ): Dialog { + val view = LayoutInflater.from(context).inflate(dialogLayoutResourceId, null) + val icon: ImageView = view.requireViewById(R.id.icon) + val title: TextView = view.requireViewById(R.id.title) + val message: TextView = view.requireViewById(R.id.message) + val buttonContainer: ViewGroup = view.requireViewById(R.id.button_container) + + viewModel.icon?.let { + IconViewBinder.bind( + view = icon, + viewModel = it, + ) + icon.isVisible = true + } + ?: run { icon.isVisible = false } + + viewModel.title?.let { + TextViewBinder.bind( + view = title, + viewModel = it, + ) + title.isVisible = true + } + ?: run { title.isVisible = false } + + viewModel.message?.let { + TextViewBinder.bind( + view = message, + viewModel = it, + ) + message.isVisible = true + } + ?: run { message.isVisible = false } + + val dialog = + AlertDialog.Builder(context, R.style.LightDialogTheme) + .setView(view) + .apply { + if (viewModel.onDismissed != null || onDismissed != null) { + setOnDismissListener { + onDismissed?.invoke() + viewModel.onDismissed?.invoke() + } + } + } + .create() + + buttonContainer.removeAllViews() + viewModel.buttons.forEach { buttonViewModel -> + buttonContainer.addView( + ButtonViewBinder.create( + parent = buttonContainer, + viewModel = + buttonViewModel.copy( + onClicked = { + buttonViewModel.onClicked?.invoke() + dialog.dismiss() + }, + ), + buttonLayoutResourceId = buttonLayoutResourceId, + ) + ) + } + + dialog.show() + return dialog + } +} diff --git a/src/com/android/wallpaper/picker/common/dialog/ui/viewmodel/DialogViewModel.kt b/src/com/android/wallpaper/picker/common/dialog/ui/viewmodel/DialogViewModel.kt new file mode 100644 index 00000000..a34bf33d --- /dev/null +++ b/src/com/android/wallpaper/picker/common/dialog/ui/viewmodel/DialogViewModel.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 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.common.dialog.ui.viewmodel + +import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonViewModel +import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +data class DialogViewModel( + val icon: Icon? = null, + val title: Text? = null, + val message: Text? = null, + val buttons: List<ButtonViewModel> = emptyList(), + val onDismissed: (() -> Unit)? = null, +) diff --git a/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/ContentDescriptionViewBinder.kt b/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/ContentDescriptionViewBinder.kt new file mode 100644 index 00000000..e31852b5 --- /dev/null +++ b/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/ContentDescriptionViewBinder.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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.common.icon.ui.viewbinder + +import android.view.View +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +object ContentDescriptionViewBinder { + fun bind( + view: View, + viewModel: Text, + ) { + view.contentDescription = + when (viewModel) { + is Text.Resource -> view.context.getString(viewModel.res) + is Text.Loaded -> viewModel.text + } + } +} diff --git a/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/IconViewBinder.kt b/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/IconViewBinder.kt new file mode 100644 index 00000000..79ec5682 --- /dev/null +++ b/src/com/android/wallpaper/picker/common/icon/ui/viewbinder/IconViewBinder.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 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.common.icon.ui.viewbinder + +import android.widget.ImageView +import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +object IconViewBinder { + fun bind( + view: ImageView, + viewModel: Icon, + ) { + when (viewModel) { + is Icon.Resource -> view.setImageResource(viewModel.res) + is Icon.Loaded -> view.setImageDrawable(viewModel.drawable) + } + + view.contentDescription = + when (viewModel.contentDescription) { + is Text.Resource -> + view.context.getString((viewModel.contentDescription as Text.Resource).res) + is Text.Loaded -> (viewModel.contentDescription as Text.Loaded).text + null -> null + } + } +} diff --git a/src/com/android/wallpaper/picker/common/icon/ui/viewmodel/Icon.kt b/src/com/android/wallpaper/picker/common/icon/ui/viewmodel/Icon.kt new file mode 100644 index 00000000..aa42e46a --- /dev/null +++ b/src/com/android/wallpaper/picker/common/icon/ui/viewmodel/Icon.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 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.common.icon.ui.viewmodel + +import android.graphics.drawable.Drawable +import androidx.annotation.DrawableRes +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +sealed class Icon( + open val contentDescription: Text?, +) { + data class Resource( + @DrawableRes val res: Int, + override val contentDescription: Text?, + ) : + Icon( + contentDescription = contentDescription, + ) + + data class Loaded( + val drawable: Drawable, + override val contentDescription: Text?, + ) : + Icon( + contentDescription = contentDescription, + ) +} diff --git a/src/com/android/wallpaper/picker/common/text/ui/viewbinder/TextViewBinder.kt b/src/com/android/wallpaper/picker/common/text/ui/viewbinder/TextViewBinder.kt new file mode 100644 index 00000000..2b58bbef --- /dev/null +++ b/src/com/android/wallpaper/picker/common/text/ui/viewbinder/TextViewBinder.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 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.common.text.ui.viewbinder + +import android.widget.TextView +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text + +object TextViewBinder { + fun bind( + view: TextView, + viewModel: Text, + ) { + when (viewModel) { + is Text.Resource -> view.setText(viewModel.res) + is Text.Loaded -> view.text = viewModel.text + } + } +} diff --git a/src/com/android/wallpaper/picker/common/text/ui/viewmodel/Text.kt b/src/com/android/wallpaper/picker/common/text/ui/viewmodel/Text.kt new file mode 100644 index 00000000..fc423e3e --- /dev/null +++ b/src/com/android/wallpaper/picker/common/text/ui/viewmodel/Text.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 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.common.text.ui.viewmodel + +import android.content.Context +import androidx.annotation.StringRes + +sealed class Text { + data class Resource( + @StringRes val res: Int, + ) : Text() + + data class Loaded( + val text: String, + ) : Text() + + fun asString(context: Context): String { + return when (this) { + is Resource -> context.getString(res) + is Loaded -> text + } + } + + companion object { + /** + * Returns `true` if the given [Text] instances evaluate to the values; `false` otherwise. + */ + fun evaluationEquals( + context: Context, + first: Text?, + second: Text?, + ): Boolean { + return first?.asString(context) == second?.asString(context) + } + } +} diff --git a/src/com/android/wallpaper/picker/customization/data/content/WallpaperClient.kt b/src/com/android/wallpaper/picker/customization/data/content/WallpaperClient.kt new file mode 100644 index 00000000..e849426b --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/data/content/WallpaperClient.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 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.customization.data.content + +import android.graphics.Bitmap +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import kotlinx.coroutines.flow.Flow + +/** Defines interface for classes that can interact with the Wallpaper API. */ +interface WallpaperClient { + + /** Lists the most recent wallpapers. The first one is the most recent (current) wallpaper. */ + fun recentWallpapers( + destination: WallpaperDestination, + limit: Int, + ): Flow<List<WallpaperModel>> + + /** Returns the selected wallpaper. */ + suspend fun getCurrentWallpaper( + destination: WallpaperDestination, + ): WallpaperModel + + /** + * Asynchronously sets the wallpaper to the one with the given ID. + * + * @param destination The screen to set the wallpaper on. + * @param wallpaperId The ID of the wallpaper to set. + * @param onDone A callback to invoke when setting is done. + */ + suspend fun setWallpaper( + destination: WallpaperDestination, + wallpaperId: String, + onDone: () -> Unit + ) + + /** Returns a thumbnail for the wallpaper with the given ID. */ + suspend fun loadThumbnail(wallpaperId: String): Bitmap? +} diff --git a/src/com/android/wallpaper/picker/customization/data/content/WallpaperClientImpl.kt b/src/com/android/wallpaper/picker/customization/data/content/WallpaperClientImpl.kt new file mode 100644 index 00000000..e85cdfd8 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/data/content/WallpaperClientImpl.kt @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2023 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.customization.data.content + +import android.content.ContentResolver +import android.content.ContentValues +import android.content.Context +import android.database.ContentObserver +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri +import android.util.Log +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import java.io.IOException +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.launch + +class WallpaperClientImpl( + private val context: Context, +) : WallpaperClient { + + override fun recentWallpapers( + destination: WallpaperDestination, + limit: Int, + ): Flow<List<WallpaperModel>> { + return callbackFlow { + suspend fun queryAndSend(limit: Int) { + send(queryRecentWallpapers(destination = destination, limit = limit)) + } + + val contentObserver = + object : ContentObserver(null) { + override fun onChange(selfChange: Boolean) { + launch { queryAndSend(limit = limit) } + } + } + + context.contentResolver.registerContentObserver( + LIST_RECENTS_URI, + /* notifyForDescendants= */ true, + contentObserver, + ) + queryAndSend(limit = limit) + + awaitClose { context.contentResolver.unregisterContentObserver(contentObserver) } + } + } + + override suspend fun getCurrentWallpaper( + destination: WallpaperDestination, + ): WallpaperModel { + return queryRecentWallpapers(destination = destination, limit = 1).first() + } + + override suspend fun setWallpaper( + destination: WallpaperDestination, + wallpaperId: String, + onDone: () -> Unit + ) { + val updateValues = ContentValues() + updateValues.put(KEY_ID, wallpaperId) + updateValues.put(KEY_SCREEN, destination.asString()) + val updatedRowCount = context.contentResolver.update(SET_WALLPAPER_URI, updateValues, null) + if (updatedRowCount == 0) { + Log.e(TAG, "Error setting wallpaper: $wallpaperId") + } + onDone.invoke() + } + + private suspend fun queryRecentWallpapers( + destination: WallpaperDestination, + limit: Int, + ): List<WallpaperModel> { + context.contentResolver + .query( + LIST_RECENTS_URI.buildUpon().appendPath(destination.asString()).build(), + arrayOf( + KEY_ID, + KEY_PLACEHOLDER_COLOR, + ), + null, + null, + ) + .use { cursor -> + if (cursor == null || cursor.count == 0) { + return emptyList() + } + + return buildList { + val idColumnIndex = cursor.getColumnIndex(KEY_ID) + val placeholderColorColumnIndex = cursor.getColumnIndex(KEY_PLACEHOLDER_COLOR) + while (cursor.moveToNext() && size < limit) { + val wallpaperId = cursor.getString(idColumnIndex) + val placeholderColor = cursor.getInt(placeholderColorColumnIndex) + add( + WallpaperModel( + wallpaperId = wallpaperId, + placeholderColor = placeholderColor, + ) + ) + } + } + } + } + + override suspend fun loadThumbnail( + wallpaperId: String, + ): Bitmap? { + try { + // We're already using this in a suspend function, so we're okay. + @Suppress("BlockingMethodInNonBlockingContext") + context.contentResolver + .openFile( + GET_THUMBNAIL_BASE_URI.buildUpon().appendPath(wallpaperId).build(), + "r", + null, + ) + .use { file -> + if (file == null) { + Log.e(TAG, "Error getting wallpaper preview: $wallpaperId") + } else { + return BitmapFactory.decodeFileDescriptor(file.fileDescriptor) + } + } + } catch (e: IOException) { + Log.e(TAG, "Error getting wallpaper preview: $wallpaperId", e) + } + + return null + } + + private fun WallpaperDestination.asString(): String { + return when (this) { + WallpaperDestination.BOTH -> SCREEN_ALL + WallpaperDestination.HOME -> SCREEN_HOME + WallpaperDestination.LOCK -> SCREEN_LOCK + } + } + + companion object { + private const val TAG = "WallpaperClientImpl" + private const val AUTHORITY = "com.google.android.apps.wallpaper.recents" + + /** Path for making a content provider request to set the wallpaper. */ + private const val PATH_SET_WALLPAPER = "set_recent_wallpaper" + /** Path for making a content provider request to query for the recent wallpapers. */ + private const val PATH_LIST_RECENTS = "list_recent" + /** Path for making a content provider request to query for the thumbnail of a wallpaper. */ + private const val PATH_GET_THUMBNAIL = "thumb" + + private val BASE_URI = + Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build() + /** [Uri] for making a content provider request to set the wallpaper. */ + private val SET_WALLPAPER_URI = BASE_URI.buildUpon().appendPath(PATH_SET_WALLPAPER).build() + /** [Uri] for making a content provider request to query for the recent wallpapers. */ + private val LIST_RECENTS_URI = BASE_URI.buildUpon().appendPath(PATH_LIST_RECENTS).build() + /** + * [Uri] for making a content provider request to query for the thumbnail of a wallpaper. + */ + private val GET_THUMBNAIL_BASE_URI = + BASE_URI.buildUpon().appendPath(PATH_GET_THUMBNAIL).build() + + /** Key for a parameter used to pass the wallpaper ID to/from the content provider. */ + private const val KEY_ID = "id" + /** Key for a parameter used to pass the screen to/from the content provider. */ + private const val KEY_SCREEN = "screen" + private const val SCREEN_ALL = "all_screens" + private const val SCREEN_HOME = "home_screen" + private const val SCREEN_LOCK = "lock_screen" + /** + * Key for a parameter used to get the placeholder color for a wallpaper from the content + * provider. + */ + private const val KEY_PLACEHOLDER_COLOR = "placeholder_color" + } +} diff --git a/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepository.kt b/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepository.kt new file mode 100644 index 00000000..6234fa53 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepository.kt @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2023 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.customization.data.repository + +import android.graphics.Bitmap +import com.android.wallpaper.picker.customization.data.content.WallpaperClient +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext + +/** Encapsulates access to wallpaper-related data. */ +class WallpaperRepository( + private val scope: CoroutineScope, + private val client: WallpaperClient, + private val backgroundDispatcher: CoroutineDispatcher, +) { + /** The ID of the currently-selected wallpaper. */ + fun selectedWallpaperId( + destination: WallpaperDestination, + ): StateFlow<String> { + return client + .recentWallpapers(destination = destination, limit = 1) + .map { previews -> previews.first().wallpaperId } + .stateIn( + scope = scope, + started = SharingStarted.WhileSubscribed(), + initialValue = + runBlocking { + client.getCurrentWallpaper(destination = destination).wallpaperId + }, + ) + } + + private val _selectingWallpaperId = + MutableStateFlow<Map<WallpaperDestination, String?>>(emptyMap()) + /** + * The ID of the wallpaper that is in the process of becoming the selected wallpaper or `null` + * if no such transaction is currently taking place. + */ + val selectingWallpaperId: StateFlow<Map<WallpaperDestination, String?>> = + _selectingWallpaperId.asStateFlow() + + /** Lists the most recent wallpapers. The first one is the most recent (current) wallpaper. */ + fun recentWallpapers( + destination: WallpaperDestination, + limit: Int, + ): Flow<List<WallpaperModel>> { + return client + .recentWallpapers(destination = destination, limit = limit) + .flowOn(backgroundDispatcher) + } + + /** Returns a thumbnail for the wallpaper with the given ID. */ + suspend fun loadThumbnail(wallpaperId: String): Bitmap? { + return withContext(backgroundDispatcher) { client.loadThumbnail(wallpaperId) } + } + + /** Sets the wallpaper to the one with the given ID. */ + suspend fun setWallpaper( + destination: WallpaperDestination, + wallpaperId: String, + ) { + _selectingWallpaperId.value = + _selectingWallpaperId.value.toMutableMap().apply { this[destination] = wallpaperId } + withContext(backgroundDispatcher) { + client.setWallpaper( + destination = destination, + wallpaperId = wallpaperId, + ) { + _selectingWallpaperId.value = + _selectingWallpaperId.value.toMutableMap().apply { this[destination] = null } + } + } + } +} diff --git a/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractor.kt b/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractor.kt new file mode 100644 index 00000000..d9e2ef64 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractor.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2023 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.customization.domain.interactor + +import android.graphics.Bitmap +import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map + +/** Handles business logic for wallpaper-related use-cases. */ +class WallpaperInteractor( + private val repository: WallpaperRepository, + /** Returns whether wallpaper picker should handle reload */ + val shouldHandleReload: () -> Boolean = { true }, +) { + /** Returns a flow that is updated whenever the wallpaper has been updated */ + fun wallpaperUpdateEvents(screen: CustomizationSections.Screen): Flow<WallpaperModel> { + return when (screen) { + CustomizationSections.Screen.LOCK_SCREEN -> + previews(WallpaperDestination.LOCK, 1).map { recentWallpapers -> + recentWallpapers[0] + } + CustomizationSections.Screen.HOME_SCREEN -> + previews(WallpaperDestination.HOME, 1).map { recentWallpapers -> + recentWallpapers[0] + } + } + } + + /** Returns the ID of the currently-selected wallpaper. */ + fun selectedWallpaperId( + destination: WallpaperDestination, + ): StateFlow<String> { + return repository.selectedWallpaperId(destination = destination) + } + + /** + * Returns the ID of the wallpaper that is in the process of becoming the selected wallpaper or + * `null` if no such transaction is currently taking place. + */ + fun selectingWallpaperId( + destination: WallpaperDestination, + ): Flow<String?> { + return repository.selectingWallpaperId.map { it[destination] } + } + + /** + * Lists the [maxResults] most recent wallpapers. + * + * The first one is the most recent (current) wallpaper. + */ + fun previews( + destination: WallpaperDestination, + maxResults: Int, + ): Flow<List<WallpaperModel>> { + return repository + .recentWallpapers( + destination = destination, + limit = maxResults, + ) + .map { previews -> + if (previews.size > maxResults) { + previews.subList(0, maxResults) + } else { + previews + } + } + } + + /** Sets the wallpaper to the one with the given ID. */ + suspend fun setWallpaper( + destination: WallpaperDestination, + wallpaperId: String, + ) { + repository.setWallpaper( + destination = destination, + wallpaperId = wallpaperId, + ) + } + + /** Returns a thumbnail for the wallpaper with the given ID. */ + suspend fun loadThumbnail(wallpaperId: String): Bitmap? { + return repository.loadThumbnail( + wallpaperId = wallpaperId, + ) + } +} diff --git a/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorer.kt b/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorer.kt new file mode 100644 index 00000000..7c23cfed --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorer.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2023 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.customization.domain.interactor + +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer +import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore +import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.launch + +/** Stores and restores undo snapshots for wallpaper state. */ +class WallpaperSnapshotRestorer( + private val scope: CoroutineScope, + private val interactor: WallpaperInteractor, +) : SnapshotRestorer { + + private var store: SnapshotStore = SnapshotStore.NOOP + + override suspend fun setUpSnapshotRestorer( + store: SnapshotStore, + ): RestorableSnapshot { + this.store = store + startObserving() + return snapshot() + } + + override suspend fun restoreToSnapshot( + snapshot: RestorableSnapshot, + ) { + val homeWallpaperId = snapshot.args[SELECTED_HOME_SCREEN_WALLPAPER_ID] + if (!homeWallpaperId.isNullOrEmpty()) { + interactor.setWallpaper( + destination = WallpaperDestination.HOME, + wallpaperId = homeWallpaperId + ) + } + + val lockWallpaperId = snapshot.args[SELECTED_LOCK_SCREEN_WALLPAPER_ID] + if (!lockWallpaperId.isNullOrEmpty()) { + interactor.setWallpaper( + destination = WallpaperDestination.LOCK, + wallpaperId = lockWallpaperId + ) + } + } + + private fun startObserving() { + scope.launch { + combine( + interactor.selectedWallpaperId(destination = WallpaperDestination.HOME), + interactor.selectedWallpaperId(destination = WallpaperDestination.LOCK), + ::Pair, + ) + .drop(1) // We skip the first value because it's the same as the initial. + .collect { (homeWallpaperId, lockWallpaperId) -> + store.store( + snapshot( + homeWallpaperId, + lockWallpaperId, + ) + ) + } + } + } + + private fun snapshot( + homeWallpaperId: String = querySelectedWallpaperId(destination = WallpaperDestination.HOME), + lockWallpaperId: String = querySelectedWallpaperId(destination = WallpaperDestination.LOCK), + ): RestorableSnapshot { + return RestorableSnapshot( + args = + buildMap { + put( + SELECTED_HOME_SCREEN_WALLPAPER_ID, + homeWallpaperId, + ) + put( + SELECTED_LOCK_SCREEN_WALLPAPER_ID, + lockWallpaperId, + ) + } + ) + } + + private fun querySelectedWallpaperId(destination: WallpaperDestination): String { + return interactor.selectedWallpaperId(destination = destination).value + } + + companion object { + private const val SELECTED_HOME_SCREEN_WALLPAPER_ID = "selected_home_screen_wallpaper_id" + private const val SELECTED_LOCK_SCREEN_WALLPAPER_ID = "selected_lock_screen_wallpaper_id" + } +} diff --git a/src/com/android/wallpaper/picker/customization/shared/model/WallpaperDestination.kt b/src/com/android/wallpaper/picker/customization/shared/model/WallpaperDestination.kt new file mode 100644 index 00000000..89d5af4e --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/shared/model/WallpaperDestination.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023 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.customization.shared.model + +/** Enumerates all known wallpaper destinations. */ +enum class WallpaperDestination { + /** Both [HOME] and [LOCK] destinations. */ + BOTH, + /** The home screen wallpaper. */ + HOME, + /** The lock screen wallpaper. */ + LOCK, +} diff --git a/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoDialogViewModel.kt b/src/com/android/wallpaper/picker/customization/shared/model/WallpaperModel.kt index b7f754b5..a0d8b38d 100644 --- a/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoDialogViewModel.kt +++ b/src/com/android/wallpaper/picker/customization/shared/model/WallpaperModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. @@ -15,10 +15,10 @@ * */ -package com.android.wallpaper.picker.undo.ui.viewmodel +package com.android.wallpaper.picker.customization.shared.model -/** Models the UI state for an undo confirmation dialog. */ -data class UndoDialogViewModel( - val onConfirmed: () -> Unit, - val onDismissed: () -> Unit, +/** Models a single wallpaper preview. */ +data class WallpaperModel( + val wallpaperId: String, + val placeholderColor: Int, ) diff --git a/src/com/android/wallpaper/picker/customization/ui/binder/CustomizationPickerBinder.kt b/src/com/android/wallpaper/picker/customization/ui/binder/CustomizationPickerBinder.kt index 53c8375b..be036bb4 100644 --- a/src/com/android/wallpaper/picker/customization/ui/binder/CustomizationPickerBinder.kt +++ b/src/com/android/wallpaper/picker/customization/ui/binder/CustomizationPickerBinder.kt @@ -30,17 +30,30 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.wallpaper.R import com.android.wallpaper.model.CustomizationSectionController -import com.android.wallpaper.model.WallpaperSectionController import com.android.wallpaper.picker.SectionView -import com.android.wallpaper.picker.customization.ui.section.ScreenPreviewSectionController import com.android.wallpaper.picker.customization.ui.viewmodel.CustomizationPickerViewModel import com.android.wallpaper.picker.undo.ui.binder.RevertToolbarButtonBinder +import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.launch typealias SectionController = CustomizationSectionController<*> /** Binds view to view-model for the customization picker. */ object CustomizationPickerBinder { + + /** + * Binds the given view and view-model, keeping the UI up-to-date and listening to user input. + * + * @param view The root of the UI to keep up-to-date and observe for user input. + * @param toolbarViewId The view ID of the toolbar view. + * @param viewModel The view-model to observe UI state from and report user input to. + * @param lifecycleOwner An owner of the lifecycle, so we can stop doing work when the lifecycle + * cleans up. + * @param sectionControllerProvider A function that can provide the list of [SectionController] + * instances to show, based on the given passed-in value of "isOnLockScreen". + * @return A [DisposableHandle] to use to dispose of the binding before another binding is about + * to be created by a subsequent call to this function. + */ @JvmStatic fun bind( view: View, @@ -48,7 +61,7 @@ object CustomizationPickerBinder { viewModel: CustomizationPickerViewModel, lifecycleOwner: LifecycleOwner, sectionControllerProvider: (isOnLockScreen: Boolean) -> List<SectionController>, - ) { + ): DisposableHandle { RevertToolbarButtonBinder.bind( view = view.requireViewById(toolbarViewId), viewModel = viewModel.undo, @@ -77,68 +90,82 @@ object CustomizationPickerBinder { topMargin = 0 } - lifecycleOwner.lifecycleScope.launch { - lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { - viewModel.isOnLockScreen.collect { isOnLockScreen -> - // These are the available section controllers we should use now. - val newSectionControllers = - sectionControllerProvider.invoke(isOnLockScreen).filter { - it.isAvailable(view.context) - } + val job = + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.isOnLockScreen.collect { isOnLockScreen -> + // These are the available section controllers we should use now. + val newSectionControllers = + sectionControllerProvider.invoke(isOnLockScreen).filter { + it.isAvailable(view.context) + } - check( - newSectionControllers[0] is WallpaperSectionController || - newSectionControllers[0] is ScreenPreviewSectionController - ) { - "The first section must always be the preview or the assumption below" + - " must be updated." - } + check( + newSectionControllers[0].shouldRetainInstanceWhenSwitchingTabs() + ) { + "We are not recreating the first section when the users switching" + + " between the home screen and lock screen tab. The first" + + " section should always retain." + } - val firstTime = sectionContainer.childCount == 0 - if (!firstTime) { - // Remove all views, except the very first one, which we assume is for - // the wallpaper preview section. - sectionContainer.removeViews(1, sectionContainer.childCount - 1) + val firstTime = sectionContainer.childCount == 0 + if (!firstTime) { + // Remove all views, except the very first one, which we assume is + // for + // the wallpaper preview section. + sectionContainer.removeViews(1, sectionContainer.childCount - 1) - // The old controllers for the removed views should be released, except - // for the very first one, which is for the wallpaper preview section; - // that one we keep but just tell it that we switched screens. - sectionContainer.children - .mapNotNull { it.tag as? SectionController } - .forEachIndexed { index, oldController -> - if (index == 0) { - // We assume that index 0 is the wallpaper preview section. - // We keep it because it's an expensive section (as it needs - // to maintain a wallpaper connection that seems to be - // making assumptions about its SurfaceView always remaining - // attached to the window). - oldController.onScreenSwitched(isOnLockScreen) - } else { - // All other old controllers will be thrown out so let's - // release them. - oldController.release() + // The old controllers for the removed views should be released, + // except + // for the very first one, which is for the wallpaper preview + // section; + // that one we keep but just tell it that we switched screens. + sectionContainer.children + .mapNotNull { it.tag as? SectionController } + .forEachIndexed { index, oldController -> + if (index == 0) { + // We assume that index 0 is the wallpaper preview + // section. + // We keep it because it's an expensive section (as it + // needs + // to maintain a wallpaper connection that seems to be + // making assumptions about its SurfaceView always + // remaining + // attached to the window). + oldController.onScreenSwitched(isOnLockScreen) + } else { + // All other old controllers will be thrown out so let's + // release them. + oldController.release() + } } - } - } + } - // Let's add the new controllers and views. - newSectionControllers.forEachIndexed { index, controller -> - if (firstTime || index > 0) { - val addedView = controller.createView(view.context, isOnLockScreen) - addedView.tag = controller - sectionContainer.addView(addedView) + // Let's add the new controllers and views. + newSectionControllers.forEachIndexed { index, controller -> + if (firstTime || index > 0) { + val addedView = + controller.createView( + view.context, + CustomizationSectionController.ViewCreationParams( + isOnLockScreen = isOnLockScreen, + ) + ) + addedView?.tag = controller + sectionContainer.addView(addedView) + } } } } } - } - // This happens when the lifecycle is stopped. - sectionContainer.children - .mapNotNull { it.tag as? CustomizationSectionController<out SectionView> } - .forEach { controller -> controller.release() } - sectionContainer.removeAllViews() - } + // This happens when the lifecycle is stopped. + sectionContainer.children + .mapNotNull { it.tag as? CustomizationSectionController<out SectionView> } + .forEach { controller -> controller.release() } + sectionContainer.removeAllViews() + } + return DisposableHandle { job.cancel() } } } diff --git a/src/com/android/wallpaper/picker/customization/ui/binder/ScreenPreviewBinder.kt b/src/com/android/wallpaper/picker/customization/ui/binder/ScreenPreviewBinder.kt index 9df609eb..a703b9a0 100644 --- a/src/com/android/wallpaper/picker/customization/ui/binder/ScreenPreviewBinder.kt +++ b/src/com/android/wallpaper/picker/customization/ui/binder/ScreenPreviewBinder.kt @@ -23,18 +23,22 @@ import android.content.Intent import android.os.Bundle import android.service.wallpaper.WallpaperService import android.view.SurfaceView +import android.view.View +import android.view.ViewGroup import androidx.cardview.widget.CardView import androidx.core.view.isVisible +import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.android.wallpaper.R import com.android.wallpaper.asset.Asset import com.android.wallpaper.asset.BitmapCachingAsset import com.android.wallpaper.asset.CurrentWallpaperAssetVN import com.android.wallpaper.model.LiveWallpaperInfo import com.android.wallpaper.model.WallpaperInfo +import com.android.wallpaper.module.CustomizationSections import com.android.wallpaper.picker.WorkspaceSurfaceHolderCallback import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel import com.android.wallpaper.util.ResourceUtils @@ -57,8 +61,16 @@ object ScreenPreviewBinder { id: Int, args: Bundle = Bundle.EMPTY, ) + fun destroy() } + /** + * Binds the view to the given [viewModel]. + * + * Note that if [dimWallpaper] is `true`, the wallpaper will be dimmed (to help highlight + * something that is changing on top of the wallpaper, for example, the lock screen shortcuts or + * the clock). + */ @JvmStatic fun bind( activity: Activity, @@ -66,9 +78,19 @@ object ScreenPreviewBinder { viewModel: ScreenPreviewViewModel, lifecycleOwner: LifecycleOwner, offsetToStart: Boolean, + dimWallpaper: Boolean = false, + // TODO (b/270193793): add below fields to all usages of this class & remove default values + screen: CustomizationSections.Screen = CustomizationSections.Screen.LOCK_SCREEN, + onPreviewDirty: () -> Unit = {}, ): Binding { val workspaceSurface: SurfaceView = previewView.requireViewById(R.id.workspace_surface) val wallpaperSurface: SurfaceView = previewView.requireViewById(R.id.wallpaper_surface) + wallpaperSurface.setZOrderOnTop(false) + + if (dimWallpaper) { + previewView.requireViewById<View>(R.id.wallpaper_dimming_scrim).isVisible = true + workspaceSurface.setZOrderOnTop(true) + } previewView.radius = previewView.resources.getDimension(R.dimen.wallpaper_picker_entry_card_corner_radius) @@ -78,10 +100,23 @@ object ScreenPreviewBinder { var wallpaperConnection: WallpaperConnection? = null var wallpaperInfo: WallpaperInfo? = null - lifecycleOwner.lifecycle.addObserver( - LifecycleEventObserver { _, event -> - when (event) { - Lifecycle.Event.ON_CREATE -> { + val job = + lifecycleOwner.lifecycleScope.launch { + launch { + val lifecycleObserver = + object : DefaultLifecycleObserver { + override fun onStop(owner: LifecycleOwner) { + super.onStop(owner) + wallpaperConnection?.disconnect() + } + + override fun onPause(owner: LifecycleOwner) { + super.onPause(owner) + wallpaperConnection?.setVisibility(false) + } + } + + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { previewSurfaceCallback = WorkspaceSurfaceHolderCallback( workspaceSurface, @@ -89,7 +124,9 @@ object ScreenPreviewBinder { viewModel.getInitialExtras(), ) workspaceSurface.holder.addCallback(previewSurfaceCallback) - workspaceSurface.setZOrderMediaOverlay(true) + if (!dimWallpaper) { + workspaceSurface.setZOrderMediaOverlay(true) + } wallpaperSurfaceCallback = WallpaperSurfaceCallback( @@ -114,15 +151,42 @@ object ScreenPreviewBinder { ) } wallpaperSurface.holder.addCallback(wallpaperSurfaceCallback) - wallpaperSurface.setZOrderMediaOverlay(true) + if (!dimWallpaper) { + wallpaperSurface.setZOrderMediaOverlay(true) + } + + lifecycleOwner.lifecycle.addObserver(lifecycleObserver) } - Lifecycle.Event.ON_DESTROY -> { - workspaceSurface.holder.removeCallback(previewSurfaceCallback) - previewSurfaceCallback?.cleanUp() - wallpaperSurface.holder.removeCallback(wallpaperSurfaceCallback) - wallpaperSurfaceCallback?.cleanUp() + + // Here when destroyed. + lifecycleOwner.lifecycle.removeObserver(lifecycleObserver) + workspaceSurface.holder.removeCallback(previewSurfaceCallback) + previewSurfaceCallback?.cleanUp() + wallpaperSurface.holder.removeCallback(wallpaperSurfaceCallback) + wallpaperSurfaceCallback?.cleanUp() + } + + launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + var initialWallpaperUpdate = true + viewModel.wallpaperUpdateEvents(screen)?.collect { + // Do not update screen preview on initial update,since the initial + // update results from starting or resuming the activity. + // + // In addition, update screen preview only if system color is a preset + // color. Otherwise, setting wallpaper will cause a change in wallpaper + // color and trigger a reset from system ui + if (initialWallpaperUpdate) { + initialWallpaperUpdate = false + } else if (viewModel.shouldHandleReload()) { + onPreviewDirty() + } + } } - Lifecycle.Event.ON_RESUME -> { + } + + launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { lifecycleOwner.lifecycleScope.launch { wallpaperInfo = viewModel.getWallpaperInfo() (wallpaperInfo as? LiveWallpaperInfo)?.let { liveWallpaperInfo -> @@ -162,16 +226,8 @@ object ScreenPreviewBinder { ) } } - Lifecycle.Event.ON_PAUSE -> { - wallpaperConnection?.setVisibility(false) - } - Lifecycle.Event.ON_STOP -> { - wallpaperConnection?.disconnect() - } - else -> Unit } } - ) return object : Binding { override fun show() { @@ -189,6 +245,24 @@ object ScreenPreviewBinder { override fun sendMessage(id: Int, args: Bundle) { previewSurfaceCallback?.send(id, args) } + + override fun destroy() { + job.cancel() + // We want to remove the SurfaceView from its parent and add it back. This causes + // the hierarchy to treat the SurfaceView as "dirty" which will cause it to render + // itself anew the next time the bind function is invoked. + removeAndReadd(workspaceSurface) + } + } + } + + private fun removeAndReadd(view: View) { + (view.parent as? ViewGroup)?.let { parent -> + val indexInParent = parent.indexOfChild(view) + if (indexInParent >= 0) { + parent.removeView(view) + parent.addView(view, indexInParent) + } } } diff --git a/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchOptionBinder.kt b/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchOptionBinder.kt new file mode 100644 index 00000000..11f2ede3 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchOptionBinder.kt @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2023 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.customization.ui.binder + +import android.animation.ValueAnimator +import android.view.View +import android.widget.ImageView +import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.wallpaper.R +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchOptionViewModel +import kotlinx.coroutines.launch + +/** + * Binds between the view and view-model for a single wallpaper quick switch option. + * + * The options are presented to the user in some sort of collection and clicking on one of the + * options selects that wallpaper. + */ +object WallpaperQuickSwitchOptionBinder { + + /** Binds the given view to the given view-model. */ + fun bind( + view: View, + viewModel: WallpaperQuickSwitchOptionViewModel, + lifecycleOwner: LifecycleOwner, + smallOptionWidthPx: Int, + largeOptionWidthPx: Int, + ) { + val selectionBorder: View = view.requireViewById(R.id.selection_border) + val selectionIcon: View = view.requireViewById(R.id.selection_icon) + val progressIndicator: View = view.requireViewById(R.id.progress_indicator) + val thumbnailView: ImageView = view.requireViewById(R.id.thumbnail) + val placeholder: ImageView = view.requireViewById(R.id.placeholder) + + placeholder.setBackgroundColor(viewModel.placeholderColor) + + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.onSelected.collect { onSelectedOrNull -> + view.setOnClickListener( + if (onSelectedOrNull != null) { + { onSelectedOrNull.invoke() } + } else { + null + } + ) + } + } + + launch { + // We want to skip animating the first width update. + var isFirstValue = true + viewModel.isLarge.collect { isLarge -> + updateWidth( + view = view, + targetWidthPx = if (isLarge) largeOptionWidthPx else smallOptionWidthPx, + animate = !isFirstValue, + ) + isFirstValue = false + } + } + + launch { + viewModel.isSelectionBorderVisible.collect { + selectionBorder.animatedVisibility(isVisible = it) + } + } + + launch { + viewModel.isSelectionIconVisible.collect { + selectionIcon.animatedVisibility(isVisible = it) + } + } + + launch { + viewModel.isProgressIndicatorVisible.collect { + progressIndicator.animatedVisibility(isVisible = it) + } + } + + launch { + val thumbnail = viewModel.thumbnail() + if (thumbnailView.tag != thumbnail) { + thumbnailView.tag = thumbnail + if (thumbnail != null) { + thumbnailView.setImageBitmap(thumbnail) + thumbnailView.fadeIn() + } else { + thumbnailView.fadeOut() + } + } + } + } + } + } + + /** + * Updates the view width. + * + * @param view The [View] to update. + * @param targetWidthPx The width we want the view to have. + * @param animate Whether the update should be animated. + */ + private fun updateWidth( + view: View, + targetWidthPx: Int, + animate: Boolean, + ) { + fun setWidth(widthPx: Int) { + view.updateLayoutParams { width = widthPx } + } + + if (!animate) { + setWidth(widthPx = targetWidthPx) + return + } + + ValueAnimator.ofInt( + view.width, + targetWidthPx, + ) + .apply { + addUpdateListener { setWidth(it.animatedValue as Int) } + start() + } + } + + private fun View.animatedVisibility( + isVisible: Boolean, + ) { + if (isVisible) { + fadeIn() + } else { + fadeOut() + } + } + + private fun View.fadeIn() { + if (isVisible) { + return + } + + alpha = 0f + isVisible = true + animate().alpha(1f).start() + } + + private fun View.fadeOut() { + if (!isVisible) { + return + } + + animate().alpha(0f).withEndAction { isVisible = false }.start() + } +} diff --git a/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchSectionBinder.kt b/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchSectionBinder.kt new file mode 100644 index 00000000..95f233c8 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/binder/WallpaperQuickSwitchSectionBinder.kt @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2023 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.customization.ui.binder + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.DimenRes +import androidx.core.view.doOnLayout +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.wallpaper.R +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel +import kotlinx.coroutines.launch + +/** Binds between the view and view-model for the wallpaper quick switch section. */ +object WallpaperQuickSwitchSectionBinder { + fun bind( + view: View, + viewModel: WallpaperQuickSwitchViewModel, + lifecycleOwner: LifecycleOwner, + onNavigateToFullWallpaperSelector: () -> Unit, + ) { + view.requireViewById<View>(R.id.more_wallpapers).setOnClickListener { + onNavigateToFullWallpaperSelector() + } + + val optionContainer: ViewGroup = view.requireViewById(R.id.options) + // We have to wait for the container to be laid out before we can bind it because we need + // its size to calculate the sizes of the option items. + optionContainer.doOnLayout { + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + bindOptions( + parent = optionContainer, + viewModel = viewModel, + lifecycleOwner = lifecycleOwner, + ) + } + } + } + } + } + + /** Binds the option items to the given parent. */ + private suspend fun bindOptions( + parent: ViewGroup, + viewModel: WallpaperQuickSwitchViewModel, + lifecycleOwner: LifecycleOwner, + ) { + viewModel.options.collect { options -> + // Remove all views from a previous update. + parent.removeAllViews() + + // Calculate the sizes that views should have. + val (largeOptionWidth, smallOptionWidth) = calculateSizes(parent, options.size) + + // Create, add, and bind a view for each option. + options.forEach { option -> + val optionView = + createOptionView( + parent = parent, + ) + parent.addView(optionView) + WallpaperQuickSwitchOptionBinder.bind( + view = optionView, + viewModel = option, + lifecycleOwner = lifecycleOwner, + smallOptionWidthPx = smallOptionWidth, + largeOptionWidthPx = largeOptionWidth, + ) + } + } + } + + /** + * Returns a pair where the first value is the width that we should use for the large/selected + * option and the second value is the width for the small/non-selected options. + */ + private fun calculateSizes( + parent: View, + optionCount: Int, + ): Pair<Int, Int> { + // The large/selected option is a square. Its size should be equal to the height of its + // container (with padding removed). + val largeOptionWidth = parent.height - parent.paddingTop - parent.paddingBottom + // We'll use the total (non-padded) width of the container to figure out the widths of the + // small/non-selected options. + val optionContainerWidthWithoutPadding = + parent.width - parent.paddingStart - parent.paddingEnd + // First, we will need the total of the widths of all the spacings between the options. + val spacingWidth = parent.dimensionResource(R.dimen.spacing_8dp) + val totalMarginWidths = (optionCount - 1) * spacingWidth + + val remainingSpaceForSmallOptions = + optionContainerWidthWithoutPadding - largeOptionWidth - totalMarginWidths + // One option is always large, the rest are small. + val numberOfSmallOptions = optionCount - 1 + val smallOptionWidth = + if (numberOfSmallOptions != 0) { + (remainingSpaceForSmallOptions / numberOfSmallOptions).coerceAtMost( + parent.dimensionResource(R.dimen.wallpaper_quick_switch_max_option_width) + ) + } else { + 0 + } + + return Pair(largeOptionWidth, smallOptionWidth) + } + + /** Returns a new [View] for an option, without attaching it to the view-tree. */ + private fun createOptionView( + parent: ViewGroup, + ): View { + return LayoutInflater.from(parent.context) + .inflate( + R.layout.wallpaper_quick_switch_option, + parent, + false, + ) + } + + /** Compose-inspired cnvenience alias for getting a dimension in pixels. */ + private fun View.dimensionResource( + @DimenRes res: Int, + ): Int { + return context.resources.getDimensionPixelSize(res) + } +} diff --git a/src/com/android/wallpaper/picker/customization/ui/section/ConnectedSectionController.kt b/src/com/android/wallpaper/picker/customization/ui/section/ConnectedSectionController.kt new file mode 100644 index 00000000..aae5edfe --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/section/ConnectedSectionController.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 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.customization.ui.section + +import android.annotation.SuppressLint +import android.content.Context +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import com.android.wallpaper.R +import com.android.wallpaper.model.CustomizationSectionController +import com.android.wallpaper.picker.SectionView +import java.util.* + +/** + * A section controller that renders two sections that are connected. + * + * In portrait mode, they are rendered vertically; in landscape mode, side-by-side. + */ +class ConnectedSectionController( + /** First section. */ + private val firstSectionController: CustomizationSectionController<out SectionView>, + /** Second section. */ + private val secondSectionController: CustomizationSectionController<out SectionView>, + /** Whether to flip the order of the child sections when laid out horizontally. */ + private val reverseOrderWhenHorizontal: Boolean = false, +) : CustomizationSectionController<ResponsiveLayoutSectionView> { + override fun isAvailable(context: Context): Boolean { + return firstSectionController.isAvailable(context) || + secondSectionController.isAvailable(context) + } + + @SuppressLint("InflateParams") // It's okay that we're inflating without a parent view. + override fun createView(context: Context): ResponsiveLayoutSectionView { + val view = + LayoutInflater.from(context) + .inflate( + R.layout.responsive_section, + null, + ) as ResponsiveLayoutSectionView + + val isHorizontal = view.orientation == LinearLayout.HORIZONTAL + val flipViewOrder = reverseOrderWhenHorizontal && isHorizontal + + add( + parentView = view, + childController = + if (flipViewOrder) { + secondSectionController + } else { + firstSectionController + }, + isHorizontal = isHorizontal, + isFirst = true, + ) + add( + parentView = view, + childController = + if (flipViewOrder) { + firstSectionController + } else { + secondSectionController + }, + isHorizontal = isHorizontal, + isFirst = false, + ) + + return view + } + + private fun add( + parentView: LinearLayout, + childController: CustomizationSectionController<out SectionView>, + isHorizontal: Boolean, + isFirst: Boolean, + ) { + val childView = + childController.createView( + context = parentView.context, + params = + CustomizationSectionController.ViewCreationParams( + isConnectedHorizontallyToOtherSections = isHorizontal, + ), + ) + + if (isHorizontal) { + // We want each child to stretch to fill an equal amount as the other children. + childView.layoutParams = + LinearLayout.LayoutParams( + /* width= */ 0, + /* height= */ LinearLayout.LayoutParams.WRAP_CONTENT, + /* weight= */ 1f, + ) + + val isLeftToRight = + TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == + View.LAYOUT_DIRECTION_LTR + childView.setBackgroundResource( + if (isLeftToRight) { + // In left-to-right layouts, the first item is on the left. + if (isFirst) { + R.drawable.leftmost_connected_section_background + } else { + R.drawable.rightmost_connected_section_background + } + } else { + // In right-to-left layouts, the first item is on the right. + if (isFirst) { + R.drawable.rightmost_connected_section_background + } else { + R.drawable.leftmost_connected_section_background + } + } + ) + } + + parentView.addView(childView) + } +} diff --git a/src/com/android/wallpaper/picker/customization/ui/section/ResponsiveLayoutSectionView.kt b/src/com/android/wallpaper/picker/customization/ui/section/ResponsiveLayoutSectionView.kt new file mode 100644 index 00000000..52469468 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/section/ResponsiveLayoutSectionView.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 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.customization.ui.section + +import android.content.Context +import android.util.AttributeSet +import com.android.wallpaper.picker.SectionView + +class ResponsiveLayoutSectionView( + context: Context, + attrs: AttributeSet?, +) : + SectionView( + context, + attrs, + ) diff --git a/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewSectionController.kt b/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewSectionController.kt index 6cb7d068..821c5bd8 100644 --- a/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewSectionController.kt +++ b/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewSectionController.kt @@ -19,19 +19,23 @@ package com.android.wallpaper.picker.customization.ui.section import android.annotation.SuppressLint import android.app.Activity -import android.app.WallpaperColors import android.content.Context +import android.os.Bundle import android.view.LayoutInflater +import android.view.View import androidx.cardview.widget.CardView +import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.lifecycleScope +import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants import com.android.wallpaper.R import com.android.wallpaper.model.CustomizationSectionController import com.android.wallpaper.model.WallpaperColorsViewModel import com.android.wallpaper.model.WallpaperInfo import com.android.wallpaper.module.CurrentWallpaperInfoFactory import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.CategorySelectorFragment +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel import com.android.wallpaper.util.DisplayUtils @@ -44,19 +48,28 @@ import kotlinx.coroutines.withContext /** Controls the screen preview section. */ @OptIn(ExperimentalCoroutinesApi::class) -class ScreenPreviewSectionController( +open class ScreenPreviewSectionController( private val activity: Activity, private val lifecycleOwner: LifecycleOwner, private val initialScreen: CustomizationSections.Screen, private val wallpaperInfoFactory: CurrentWallpaperInfoFactory, private val colorViewModel: WallpaperColorsViewModel, private val displayUtils: DisplayUtils, + private val navigator: CustomizationSectionController.CustomizationSectionNavigationController, + private val wallpaperInteractor: WallpaperInteractor, ) : CustomizationSectionController<ScreenPreviewView> { private lateinit var lockScreenBinding: ScreenPreviewBinder.Binding private lateinit var homeScreenBinding: ScreenPreviewBinder.Binding - override fun isAvailable(context: Context?): Boolean { + /** Override to hide the lock screen clock preview. */ + open val hideLockScreenClockPreview = false + + override fun shouldRetainInstanceWhenSwitchingTabs(): Boolean { + return true + } + + override fun isAvailable(context: Context): Boolean { // Assumption is that, if this section controller is included, we are using the revamped UI // so it should always be shown. return true @@ -70,6 +83,9 @@ class ScreenPreviewSectionController( R.layout.screen_preview_section, /* parent= */ null, ) as ScreenPreviewView + val onClickListener = + View.OnClickListener { navigator.navigateTo(CategorySelectorFragment()) } + view.setOnClickListener(onClickListener) val lockScreenView: CardView = view.requireViewById(R.id.lock_preview) val homeScreenView: CardView = view.requireViewById(R.id.home_preview) @@ -95,7 +111,7 @@ class ScreenPreviewSectionController( loadInitialColors( context = context, wallpaper = wallpaper, - liveData = colorViewModel.lockWallpaperColors, + screen = CustomizationSections.Screen.LOCK_SCREEN, ) continuation.resume(wallpaper, null) }, @@ -104,11 +120,29 @@ class ScreenPreviewSectionController( } }, onWallpaperColorChanged = { colors -> - colorViewModel.lockWallpaperColors.value = colors + colorViewModel.setLockWallpaperColors(colors) + }, + initialExtrasProvider = { + Bundle().apply { + // Hide the clock from the system UI rendered preview so we can + // place the carousel on top of it. + putBoolean( + ClockPreviewConstants.KEY_HIDE_CLOCK, + hideLockScreenClockPreview, + ) + } }, + wallpaperInteractor = wallpaperInteractor, ), lifecycleOwner = lifecycleOwner, - offsetToStart = displayUtils.isOnWallpaperDisplay(activity), + offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity), + screen = CustomizationSections.Screen.LOCK_SCREEN, + onPreviewDirty = { + // only the visible binding should recreate the activity so it's not done twice + if (lockScreenView.isVisible) { + activity.recreate() + } + }, ) homeScreenBinding = ScreenPreviewBinder.bind( @@ -132,7 +166,7 @@ class ScreenPreviewSectionController( loadInitialColors( context = context, wallpaper = wallpaper, - liveData = colorViewModel.homeWallpaperColors, + screen = CustomizationSections.Screen.HOME_SCREEN ) continuation.resume(wallpaper, null) }, @@ -141,11 +175,19 @@ class ScreenPreviewSectionController( } }, onWallpaperColorChanged = { colors -> - colorViewModel.lockWallpaperColors.value = colors + colorViewModel.setHomeWallpaperColors(colors) }, + wallpaperInteractor = wallpaperInteractor, ), lifecycleOwner = lifecycleOwner, - offsetToStart = displayUtils.isOnWallpaperDisplay(activity), + offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity), + screen = CustomizationSections.Screen.HOME_SCREEN, + onPreviewDirty = { + // only the visible binding should recreate the activity so it's not done twice + if (homeScreenView.isVisible) { + activity.recreate() + } + }, ) onScreenSwitched(isOnLockScreen = initialScreen == CustomizationSections.Screen.LOCK_SCREEN) @@ -166,11 +208,19 @@ class ScreenPreviewSectionController( private fun loadInitialColors( context: Context, wallpaper: WallpaperInfo?, - liveData: MutableLiveData<WallpaperColors>, + screen: CustomizationSections.Screen, ) { lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { val colors = wallpaper?.computeColorInfo(context)?.get()?.wallpaperColors - withContext(Dispatchers.Main) { liveData.value = colors } + withContext(Dispatchers.Main) { + if (colors != null) { + if (screen == CustomizationSections.Screen.LOCK_SCREEN) { + colorViewModel.setLockWallpaperColors(colors) + } else { + colorViewModel.setHomeWallpaperColors(colors) + } + } + } } } } diff --git a/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewView.kt b/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewView.kt index ee55de41..c9e8022b 100644 --- a/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewView.kt +++ b/src/com/android/wallpaper/picker/customization/ui/section/ScreenPreviewView.kt @@ -19,7 +19,11 @@ package com.android.wallpaper.picker.customization.ui.section import android.content.Context import android.util.AttributeSet +import android.view.MotionEvent +import android.view.ViewConfiguration import com.android.wallpaper.picker.SectionView +import kotlin.math.pow +import kotlin.math.sqrt class ScreenPreviewView( context: Context, @@ -28,4 +32,57 @@ class ScreenPreviewView( SectionView( context, attrs, - ) + ) { + + private var downX = 0f + private var downY = 0f + + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + if (event.actionMasked == MotionEvent.ACTION_DOWN) { + downX = event.x + downY = event.y + } + + // We want to intercept clicks so the Carousel MotionLayout child doesn't prevent users from + // clicking on the screen preview. + if (isClick(event, downX, downY)) { + return performClick() + } + + return super.onInterceptTouchEvent(event) + } + + companion object { + private fun isClick(event: MotionEvent, downX: Float, downY: Float): Boolean { + return when { + // It's not a click if the event is not an UP action (though it may become one + // later, when/if an UP is received). + event.actionMasked != MotionEvent.ACTION_UP -> false + // It's not a click if too much time has passed between the down and the current + // event. + gestureElapsedTime(event) > ViewConfiguration.getTapTimeout() -> false + // It's not a click if the touch traveled too far. + distanceMoved(event, downX, downY) > ViewConfiguration.getTouchSlop() -> false + // Otherwise, this is a click! + else -> true + } + } + + /** + * Returns the distance that the pointer traveled in the touch gesture the given event is + * part of. + */ + private fun distanceMoved(event: MotionEvent, downX: Float, downY: Float): Float { + val deltaX = event.x - downX + val deltaY = event.y - downY + return sqrt(deltaX.pow(2) + deltaY.pow(2)) + } + + /** + * Returns the elapsed time since the touch gesture the given event is part of has begun. + */ + private fun gestureElapsedTime(event: MotionEvent): Long { + return event.eventTime - event.downTime + } + } +} diff --git a/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchSectionController.kt b/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchSectionController.kt new file mode 100644 index 00000000..d54e9c0e --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchSectionController.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 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.customization.ui.section + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import androidx.lifecycle.LifecycleOwner +import com.android.wallpaper.R +import com.android.wallpaper.model.CustomizationSectionController +import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.CategorySelectorFragment +import com.android.wallpaper.picker.customization.ui.binder.WallpaperQuickSwitchSectionBinder +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel + +/** Controls a section that lets the user switch wallpapers quickly. */ +class WallpaperQuickSwitchSectionController( + private val screen: CustomizationSections.Screen, + private val viewModel: WallpaperQuickSwitchViewModel, + private val lifecycleOwner: LifecycleOwner, + private val navigator: CustomizationSectionController.CustomizationSectionNavigationController, +) : CustomizationSectionController<WallpaperQuickSwitchView> { + + override fun isAvailable(context: Context): Boolean { + return true + } + + @SuppressLint("InflateParams") // We don't care that the parent is null. + override fun createView(context: Context): WallpaperQuickSwitchView { + val view = + LayoutInflater.from(context) + .inflate( + R.layout.wallpaper_quick_switch_section, + /* parent= */ null, + ) as WallpaperQuickSwitchView + viewModel.setOnLockScreen( + isLockScreenSelected = screen == CustomizationSections.Screen.LOCK_SCREEN, + ) + WallpaperQuickSwitchSectionBinder.bind( + view = view, + viewModel = viewModel, + lifecycleOwner = lifecycleOwner, + onNavigateToFullWallpaperSelector = { + navigator.navigateTo(CategorySelectorFragment()) + }, + ) + return view + } + + override fun onScreenSwitched(isOnLockScreen: Boolean) { + viewModel.setOnLockScreen(isLockScreenSelected = isOnLockScreen) + } +} diff --git a/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchView.kt b/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchView.kt new file mode 100644 index 00000000..5a23f09e --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/section/WallpaperQuickSwitchView.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 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.customization.ui.section + +import android.content.Context +import android.util.AttributeSet +import com.android.wallpaper.picker.SectionView + +class WallpaperQuickSwitchView( + context: Context, + attrs: AttributeSet?, +) : + SectionView( + context, + attrs, + ) diff --git a/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModel.kt b/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModel.kt index 7fd622cb..14c0715d 100644 --- a/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModel.kt +++ b/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModel.kt @@ -81,7 +81,22 @@ constructor( } init { - _isOnLockScreen.value = savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] ?: true + savedStateHandle.get<Boolean>(KEY_SAVED_STATE_IS_ON_LOCK_SCREEN)?.let { + _isOnLockScreen.value = it + } + } + + /** + * Sets the initial screen we should be on, unless there's already a selected screen from a + * previous saved state, in which case we ignore the passed-in one. + */ + fun setInitialScreen(onLockScreen: Boolean) { + _isOnLockScreen.value = + savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] + ?: run { + savedStateHandle[KEY_SAVED_STATE_IS_ON_LOCK_SCREEN] = onLockScreen + onLockScreen + } } companion object { diff --git a/src/com/android/wallpaper/picker/customization/ui/viewmodel/ScreenPreviewViewModel.kt b/src/com/android/wallpaper/picker/customization/ui/viewmodel/ScreenPreviewViewModel.kt index 79e18a38..1ceaa80b 100644 --- a/src/com/android/wallpaper/picker/customization/ui/viewmodel/ScreenPreviewViewModel.kt +++ b/src/com/android/wallpaper/picker/customization/ui/viewmodel/ScreenPreviewViewModel.kt @@ -20,7 +20,11 @@ package com.android.wallpaper.picker.customization.ui.viewmodel import android.app.WallpaperColors import android.os.Bundle import com.android.wallpaper.model.WallpaperInfo +import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel import com.android.wallpaper.util.PreviewUtils +import kotlinx.coroutines.flow.Flow /** Models the UI state for a preview of the home screen or lock screen. */ class ScreenPreviewViewModel( @@ -28,7 +32,19 @@ class ScreenPreviewViewModel( private val initialExtrasProvider: () -> Bundle? = { null }, private val wallpaperInfoProvider: suspend () -> WallpaperInfo?, private val onWallpaperColorChanged: (WallpaperColors?) -> Unit = {}, + // TODO (b/270193793): add below field to all usages, remove default value & make non-nullable + private val wallpaperInteractor: WallpaperInteractor? = null, ) { + /** Returns whether wallpaper picker should handle reload */ + fun shouldHandleReload(): Boolean { + return wallpaperInteractor?.let { it.shouldHandleReload() } ?: true + } + + /** Returns a flow that is updated whenever the wallpaper has been updated */ + fun wallpaperUpdateEvents(screen: CustomizationSections.Screen): Flow<WallpaperModel>? { + return wallpaperInteractor?.wallpaperUpdateEvents(screen) + } + fun getInitialExtras(): Bundle? { return initialExtrasProvider.invoke() } diff --git a/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchOptionViewModel.kt b/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchOptionViewModel.kt new file mode 100644 index 00000000..c8cb2fde --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchOptionViewModel.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 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.customization.ui.viewmodel + +import android.graphics.Bitmap +import kotlinx.coroutines.flow.Flow + +/** Models the UI state for an option in the wallpaper quick switcher. */ +data class WallpaperQuickSwitchOptionViewModel( + /** The ID of the wallpaper this option is associated with. */ + val wallpaperId: String, + /** A placeholder color to show in the option while we load the preview thumbnail. */ + val placeholderColor: Int, + /** A function to invoke to get the preview thumbnail for the option. */ + val thumbnail: suspend () -> Bitmap?, + /** + * Whether the option should be rendered as large. If `false`, the option should be rendered + * smaller. + */ + val isLarge: Flow<Boolean>, + /** Whether the progress indicator should be visible. */ + val isProgressIndicatorVisible: Flow<Boolean>, + /** Whether the selection border should be visible. */ + val isSelectionBorderVisible: Flow<Boolean>, + /** Whether the selection icon should be visible. */ + val isSelectionIconVisible: Flow<Boolean>, + /** + * A function to invoke when the option is clicked by the user. If `null`, the option is not + * clickable. + */ + val onSelected: Flow<(() -> Unit)?>, +) diff --git a/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModel.kt b/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModel.kt new file mode 100644 index 00000000..105dcff0 --- /dev/null +++ b/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModel.kt @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2023 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.customization.ui.viewmodel + +import android.os.Bundle +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.AbstractSavedStateViewModelFactory +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.savedstate.SavedStateRegistryOwner +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.launch + +/** Models UI state for views that can render wallpaper quick switching. */ +@OptIn(ExperimentalCoroutinesApi::class) +class WallpaperQuickSwitchViewModel +@VisibleForTesting +constructor( + private val interactor: WallpaperInteractor, + maxOptions: Int, +) : ViewModel() { + private val isLockScreenSelected = MutableStateFlow(false) + + private val selectedWallpaperId: Flow<String> = + isLockScreenSelected + .flatMapLatest { isOnLockScreen -> + interactor.selectedWallpaperId( + destination = + if (isOnLockScreen) { + WallpaperDestination.LOCK + } else { + WallpaperDestination.HOME + }, + ) + } + .shareIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(), + replay = 1, + ) + private val selectingWallpaperId: Flow<String?> = + isLockScreenSelected + .flatMapLatest { isOnLockScreen -> + interactor.selectingWallpaperId( + destination = + if (isOnLockScreen) { + WallpaperDestination.LOCK + } else { + WallpaperDestination.HOME + }, + ) + } + .shareIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(), + replay = 1, + ) + + val options: Flow<List<WallpaperQuickSwitchOptionViewModel>> = + isLockScreenSelected + .flatMapLatest { isOnLockScreen -> + interactor + .previews( + destination = + if (isOnLockScreen) { + WallpaperDestination.LOCK + } else { + WallpaperDestination.HOME + }, + maxResults = maxOptions, + ) + .distinctUntilChangedBy { previews -> + // Produce a key that's the same if the same set of wallpapers is available, + // even if in a different order. This is so that the view can keep from + // moving the wallpaper options around when the sort order changes as the + // user selects different wallpapers. + previews.map { preview -> preview.wallpaperId }.sorted().joinToString(",") + } + .map { previews -> + // True if any option is becoming selected following user click. + val isSomethingBecomingSelectedFlow: Flow<Boolean> = + selectingWallpaperId.distinctUntilChanged().map { it != null } + + previews.map { preview -> + // True if this option is currently selected. + val isSelectedFlow: Flow<Boolean> = + selectedWallpaperId.distinctUntilChanged().map { + it == preview.wallpaperId + } + // True if this option is becoming the selected one following user + // click. + val isBecomingSelectedFlow: Flow<Boolean> = + selectingWallpaperId.distinctUntilChanged().map { + it == preview.wallpaperId + } + + WallpaperQuickSwitchOptionViewModel( + wallpaperId = preview.wallpaperId, + placeholderColor = preview.placeholderColor, + thumbnail = { + interactor.loadThumbnail( + wallpaperId = preview.wallpaperId, + ) + }, + isLarge = + combine( + isSelectedFlow, + isBecomingSelectedFlow, + isSomethingBecomingSelectedFlow, + ) { isSelected, isBecomingSelected, isSomethingBecomingSelected + -> + // The large option is the one that's currently selected or + // the one that is becoming the selected one following user + // click. + (isSelected && !isSomethingBecomingSelected) || + isBecomingSelected + }, + // We show the progress indicator if the option is in the process of + // becoming the selected one following user click. + isProgressIndicatorVisible = isBecomingSelectedFlow, + isSelectionBorderVisible = + combine( + isSelectedFlow, + isBecomingSelectedFlow, + isSomethingBecomingSelectedFlow, + ) { isSelected, isBeingSelected, isSomethingBecomingSelected -> + // The selection border is shown for the option that is the + // one that's currently selected or the one that is becoming + // the selected one following user click. + (isSelected && !isSomethingBecomingSelected) || + isBeingSelected + }, + isSelectionIconVisible = + combine( + isSelectedFlow, + isSomethingBecomingSelectedFlow, + ) { isSelected, isSomethingBecomingSelected -> + // The selection icon is shown for the option that is + // currently selected but only if nothing else is becoming + // selected. If anything is being selected following user + // click, the selection icon is not shown on any option. + isSelected && !isSomethingBecomingSelected + }, + onSelected = + combine( + isSelectedFlow, + isBecomingSelectedFlow, + isSomethingBecomingSelectedFlow, + ) { isSelected, isBeingSelected, isSomethingBecomingSelected + -> + // An option is selectable if it is not itself becoming + // selected following user click or if nothing else is + // becoming selected but this option is not the selected + // one. + (isSomethingBecomingSelected && !isBeingSelected) || + (!isSomethingBecomingSelected && !isSelected) + } + .distinctUntilChanged() + .map { isSelectable -> + if (isSelectable) { + { + // A selectable option can become selected. + viewModelScope.launch { + interactor.setWallpaper( + destination = + if (isOnLockScreen) { + WallpaperDestination.LOCK + } else { + WallpaperDestination.HOME + }, + wallpaperId = preview.wallpaperId, + ) + } + } + } else { + // A non-selectable option cannot become selected. + null + } + } + ) + } + } + } + .shareIn( + scope = viewModelScope, + started = SharingStarted.Lazily, + replay = 1, + ) + + fun setOnLockScreen(isLockScreenSelected: Boolean) { + this.isLockScreenSelected.value = isLockScreenSelected + } + + companion object { + @JvmStatic + fun newFactory( + owner: SavedStateRegistryOwner, + defaultArgs: Bundle? = null, + interactor: WallpaperInteractor, + ): AbstractSavedStateViewModelFactory = + object : AbstractSavedStateViewModelFactory(owner, defaultArgs) { + @Suppress("UNCHECKED_CAST") + override fun <T : ViewModel> create( + key: String, + modelClass: Class<T>, + handle: SavedStateHandle, + ): T { + return WallpaperQuickSwitchViewModel( + interactor = interactor, + maxOptions = MAX_OPTIONS, + ) + as T + } + } + + /** The maximum number of options to show, including the currently-selected one. */ + private const val MAX_OPTIONS = 5 + } +} diff --git a/src/com/android/wallpaper/picker/individual/IndividualHolder.java b/src/com/android/wallpaper/picker/individual/IndividualHolder.java index c780db1e..feff2b8d 100755 --- a/src/com/android/wallpaper/picker/individual/IndividualHolder.java +++ b/src/com/android/wallpaper/picker/individual/IndividualHolder.java @@ -70,7 +70,9 @@ abstract class IndividualHolder extends ViewHolder { mTitleView.setVisibility(View.VISIBLE); mTileLayout.setContentDescription(title); } else if (firstAttribution != null) { - mTileLayout.setContentDescription(firstAttribution); + String contentDescription = wallpaper.getContentDescription(mActivity); + mTileLayout.setContentDescription( + contentDescription != null ? contentDescription : firstAttribution); } Drawable overlayIcon = wallpaper.getOverlayIcon(mActivity); diff --git a/src/com/android/wallpaper/picker/individual/IndividualPickerFragment2.kt b/src/com/android/wallpaper/picker/individual/IndividualPickerFragment2.kt index 4a21dbc2..3186eb5f 100644 --- a/src/com/android/wallpaper/picker/individual/IndividualPickerFragment2.kt +++ b/src/com/android/wallpaper/picker/individual/IndividualPickerFragment2.kt @@ -43,12 +43,14 @@ import androidx.annotation.DrawableRes import androidx.cardview.widget.CardView import androidx.core.widget.ContentLoadingProgressBar import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.wallpaper.R import com.android.wallpaper.model.Category import com.android.wallpaper.model.CategoryProvider import com.android.wallpaper.model.CategoryReceiver +import com.android.wallpaper.model.LiveWallpaperInfo import com.android.wallpaper.model.WallpaperCategory import com.android.wallpaper.model.WallpaperInfo import com.android.wallpaper.model.WallpaperRotationInitializer @@ -71,6 +73,8 @@ import com.android.wallpaper.widget.WallpaperPickerRecyclerViewAccessibilityDele import com.bumptech.glide.Glide import com.bumptech.glide.MemoryCategory import java.util.Date +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch /** Displays the Main UI for picking an individual wallpaper image. */ class IndividualPickerFragment2 : @@ -109,18 +113,20 @@ class IndividualPickerFragment2 : private lateinit var imageGrid: RecyclerView private var adapter: IndividualAdapter? = null - private lateinit var category: WallpaperCategory + private var category: WallpaperCategory? = null private var wallpaperRotationInitializer: WallpaperRotationInitializer? = null private lateinit var items: MutableList<PickerItem> private var packageStatusNotifier: PackageStatusNotifier? = null - private var isWallpapersReceived = false - private var appStatusListener: PackageStatusNotifier.Listener? = null + private var appStatusListener: PackageStatusNotifier.Listener? = null private var progressDialog: ProgressDialog? = null + private var testingMode = false private var loading: ContentLoadingProgressBar? = null + private var shouldReloadWallpapers = false private lateinit var categoryProvider: CategoryProvider + private var appliedWallpaperIds: Set<String> = setOf() /** * Staged error dialog fragments that were unable to be shown when the activity didn't allow @@ -177,14 +183,14 @@ class IndividualPickerFragment2 : return } category = fetchedCategory as WallpaperCategory - onCategoryLoaded() + category?.let { onCategoryLoaded(it) } } }, false ) } - fun onCategoryLoaded() { + fun onCategoryLoaded(category: Category) { val fragmentHost = getIndividualPickerFragmentHost() if (fragmentHost.isHostToolbarShown) { fragmentHost.setToolbarTitle(category.title) @@ -195,22 +201,12 @@ class IndividualPickerFragment2 : if (mToolbar != null && isRotationEnabled()) { setUpToolbarMenu(R.menu.individual_picker_menu) } - fetchWallpapers(false) + var shouldForceReload = false if (category.supportsThirdParty()) { - appStatusListener = - PackageStatusNotifier.Listener { pkgName: String?, status: Int -> - if ( - status != PackageStatusNotifier.PackageStatus.REMOVED || - category.containsThirdParty(pkgName) - ) { - fetchWallpapers(true) - } - } - packageStatusNotifier?.addListener( - appStatusListener, - WallpaperService.SERVICE_INTERFACE - ) + shouldForceReload = true } + fetchWallpapers(shouldForceReload) + registerPackageListener(category) } private fun fetchWallpapers(forceReload: Boolean) { @@ -218,13 +214,13 @@ class IndividualPickerFragment2 : isWallpapersReceived = false updateLoading() val context = requireContext() - category.fetchWallpapers( + category?.fetchWallpapers( context.applicationContext, { fetchedWallpapers -> isWallpapersReceived = true updateLoading() val byGroup = fetchedWallpapers.groupBy { it.getGroupName(context) } - val appliedWallpaperIds = getAppliedWallpaperIds() + appliedWallpaperIds = getAppliedWallpaperIds() byGroup.forEach { (groupName, wallpapers) -> if (!TextUtils.isEmpty(groupName)) { items.add( @@ -235,12 +231,16 @@ class IndividualPickerFragment2 : } ) } + val currentWallpaper = WallpaperManager.getInstance(context).wallpaperInfo items.addAll( wallpapers.map { - PickerItem.WallpaperItem( - it, - appliedWallpaperIds.contains(it.wallpaperId) - ) + val isApplied = + if (it is LiveWallpaperInfo) { + it.isApplied(currentWallpaper) + } else { + appliedWallpaperIds.contains(it.wallpaperId) + } + PickerItem.WallpaperItem(it, isApplied) } ) } @@ -260,6 +260,24 @@ class IndividualPickerFragment2 : ) } + private fun registerPackageListener(category: Category) { + if (category.supportsThirdParty()) { + appStatusListener = + PackageStatusNotifier.Listener { pkgName: String?, status: Int -> + if ( + status != PackageStatusNotifier.PackageStatus.REMOVED || + category.containsThirdParty(pkgName) + ) { + fetchWallpapers(true) + } + } + packageStatusNotifier?.addListener( + appStatusListener, + WallpaperService.SERVICE_INTERFACE + ) + } + } + private fun updateLoading() { if (isWallpapersReceived) { loading?.hide() @@ -293,7 +311,7 @@ class IndividualPickerFragment2 : if (isRotationEnabled()) { setUpToolbarMenu(R.menu.individual_picker_menu) } - setTitle(category.title) + setTitle(category?.title) } imageGrid = view.findViewById<View>(R.id.wallpaper_grid) as RecyclerView loading = view.findViewById(R.id.loading_indicator) @@ -328,7 +346,7 @@ class IndividualPickerFragment2 : return } // Skip if category hasn't loaded yet - if (!this::category.isInitialized) { + if (category == null) { return } if (context == null) { @@ -365,7 +383,7 @@ class IndividualPickerFragment2 : } else { SizeCalculator.getIndividualTileSize(activity!!) } - setUpImageGrid(tileSizePx) + setUpImageGrid(tileSizePx, checkNotNull(category)) imageGrid.setAccessibilityDelegateCompat( WallpaperPickerRecyclerViewAccessibilityDelegate( imageGrid, @@ -408,7 +426,7 @@ class IndividualPickerFragment2 : * Create the adapter and assign it to mImageGrid. Both mImageGrid and mCategory are guaranteed * to not be null when this method is called. */ - private fun setUpImageGrid(tileSizePx: Point) { + private fun setUpImageGrid(tileSizePx: Point, category: Category) { adapter = IndividualAdapter( items, @@ -435,6 +453,14 @@ class IndividualPickerFragment2 : imageGrid.layoutManager = gridLayoutManager } + private suspend fun fetchWallpapersIfNeeded() { + coroutineScope { + if (isWallpapersReceived && (shouldReloadWallpapers || isAppliedWallpaperChanged())) { + fetchWallpapers(true) + } + } + } + override fun onResume() { super.onResume() val preferences = InjectorProvider.getInjector().getPreferences(requireActivity()) @@ -452,10 +478,16 @@ class IndividualPickerFragment2 : parentFragmentManager, TAG_START_ROTATION_ERROR_DIALOG ) + lifecycleScope.launch { fetchWallpapersIfNeeded() } } stagedStartRotationErrorDialogFragment = null } + override fun onPause() { + shouldReloadWallpapers = category?.supportsWallpaperSetUpdates() ?: false + super.onPause() + } + override fun onDestroyView() { super.onDestroyView() getIndividualPickerFragmentHost().removeToolbarMenu() @@ -493,7 +525,7 @@ class IndividualPickerFragment2 : override fun startRotation(@NetworkPreference networkPreference: Int) { if (!isRotationEnabled()) { - Log.e(TAG, "Rotation is not enabled for this category " + category.title) + Log.e(TAG, "Rotation is not enabled for this category " + category?.title) return } @@ -628,6 +660,17 @@ class IndividualPickerFragment2 : return appliedWallpaperIds } + // TODO(b/277180178): Extract the check to another class for unit testing + private fun isAppliedWallpaperChanged(): Boolean { + // Reload wallpapers if the current wallpapers have changed + getAppliedWallpaperIds().let { + if (appliedWallpaperIds.isEmpty() || appliedWallpaperIds != it) { + return true + } + } + return false + } + sealed class PickerItem(val title: CharSequence = "") { class WallpaperItem(val wallpaperInfo: WallpaperInfo, val isApplied: Boolean) : PickerItem() diff --git a/src/com/android/wallpaper/picker/option/ui/adapter/OptionItemAdapter.kt b/src/com/android/wallpaper/picker/option/ui/adapter/OptionItemAdapter.kt new file mode 100644 index 00000000..150dc42c --- /dev/null +++ b/src/com/android/wallpaper/picker/option/ui/adapter/OptionItemAdapter.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 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.option.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.android.wallpaper.R +import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder +import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** Adapts between option items and their views. */ +class OptionItemAdapter<T>( + @LayoutRes private val layoutResourceId: Int, + private val lifecycleOwner: LifecycleOwner, + private val backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val foregroundTintSpec: OptionItemBinder.TintSpec? = null, + private val bindIcon: (View, T) -> Unit, +) : RecyclerView.Adapter<OptionItemAdapter.ViewHolder>() { + + private val items = mutableListOf<OptionItemViewModel<T>>() + + fun setItems(items: List<OptionItemViewModel<T>>) { + lifecycleOwner.lifecycleScope.launch { + val oldItems = this@OptionItemAdapter.items + val newItems = items + val diffResult = + withContext(backgroundDispatcher) { + DiffUtil.calculateDiff( + object : DiffUtil.Callback() { + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areItemsTheSame( + oldItemPosition: Int, + newItemPosition: Int + ): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.key.value == newItem.key.value + } + + override fun areContentsTheSame( + oldItemPosition: Int, + newItemPosition: Int + ): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem == newItem + } + }, + /* detectMoves= */ false, + ) + } + + oldItems.clear() + oldItems.addAll(items) + diffResult.dispatchUpdatesTo(this@OptionItemAdapter) + } + } + + class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + var disposableHandle: DisposableHandle? = null + } + + override fun getItemCount(): Int { + return items.size + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(parent.context) + .inflate( + layoutResourceId, + parent, + false, + ) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.disposableHandle?.dispose() + val item = items[position] + item.payload?.let { + bindIcon(holder.itemView.requireViewById(R.id.foreground), item.payload) + } + holder.disposableHandle = + OptionItemBinder.bind( + view = holder.itemView, + viewModel = item, + lifecycleOwner = lifecycleOwner, + foregroundTintSpec = foregroundTintSpec, + ) + } +} diff --git a/src/com/android/wallpaper/picker/option/ui/binder/OptionItemBinder.kt b/src/com/android/wallpaper/picker/option/ui/binder/OptionItemBinder.kt new file mode 100644 index 00000000..802fc62c --- /dev/null +++ b/src/com/android/wallpaper/picker/option/ui/binder/OptionItemBinder.kt @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2023 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. + * + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.wallpaper.picker.option.ui.binder + +import android.view.View +import android.view.ViewPropertyAnimator +import android.view.animation.LinearInterpolator +import android.view.animation.PathInterpolator +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.wallpaper.R +import com.android.wallpaper.picker.common.icon.ui.viewbinder.ContentDescriptionViewBinder +import com.android.wallpaper.picker.common.text.ui.viewbinder.TextViewBinder +import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.launch + +object OptionItemBinder { + /** + * Binds the given [View] to the given [OptionItemViewModel]. + * + * The child views of [view] must be named and arranged in the following manner, from top of the + * z-axis to the bottom: + * - [R.id.foreground] is the foreground drawable ([ImageView]). + * - [R.id.background] is the view in the background ([View]). + * - [R.id.selection_border] is a view rendering a border. It must have the same exact size as + * [R.id.background] ([View]) and must be placed below it on the z-axis (you read that right). + * + * The animation logic in this binder takes care of scaling up the border at the right time to + * help it peek out around the background. In order to allow for this, you may need to disable + * the clipping of child views across the view-tree using: + * ``` + * android:clipChildren="false" + * ``` + * + * Optionally, there may be an [R.id.text] [TextView] to show the text from the view-model. If + * one is not supplied, the text will be used as the content description of the icon. + * + * @param view The view; it must contain the child views described above. + * @param viewModel The view-model. + * @param lifecycleOwner The [LifecycleOwner]. + * @param animationSpec The specification for the animation. + * @param foregroundTintSpec The specification of how to tint the foreground icons. + * @return A [DisposableHandle] that must be invoked when the view is recycled. + */ + fun bind( + view: View, + viewModel: OptionItemViewModel<*>, + lifecycleOwner: LifecycleOwner, + animationSpec: AnimationSpec = AnimationSpec(), + foregroundTintSpec: TintSpec? = null, + ): DisposableHandle { + val borderView: View = view.requireViewById(R.id.selection_border) + val backgroundView: View = view.requireViewById(R.id.background) + val foregroundView: View = view.requireViewById(R.id.foreground) + val textView: TextView? = view.findViewById(R.id.text) + + if (textView != null) { + TextViewBinder.bind( + view = textView, + viewModel = viewModel.text, + ) + } else { + // Use the text as the content description of the foreground if we don't have a TextView + // dedicated to for the text. + ContentDescriptionViewBinder.bind( + view = foregroundView, + viewModel = viewModel.text, + ) + } + view.alpha = + if (viewModel.isEnabled) { + animationSpec.enabledAlpha + } else { + animationSpec.disabledAlpha + } + view.onLongClickListener = + if (viewModel.onLongClicked != null) { + View.OnLongClickListener { + viewModel.onLongClicked.invoke() + true + } + } else { + null + } + + val job = + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + // We only want to animate if the view-model is updating in response to a + // selection or deselection of the same exact option. For that, we save the + // last + // value of isSelected. + var lastSelected: Boolean? = null + + viewModel.key + .flatMapLatest { + // If the key changed, then it means that this binding is no longer + // rendering the UI for the same option as before, we nullify the + // last + // selected value to "forget" that we've ever seen a value for + // isSelected, + // effectively starting anew so the first update doesn't animate. + lastSelected = null + viewModel.isSelected + } + .collect { isSelected -> + if (foregroundTintSpec != null && foregroundView is ImageView) { + if (isSelected) { + foregroundView.setColorFilter( + foregroundTintSpec.selectedColor + ) + } else { + foregroundView.setColorFilter( + foregroundTintSpec.unselectedColor + ) + } + } + + animatedSelection( + animationSpec = animationSpec, + borderView = borderView, + contentView = backgroundView, + isSelected = isSelected, + animate = lastSelected != null && lastSelected != isSelected, + ) + lastSelected = isSelected + } + } + + launch { + viewModel.onClicked.collect { onClicked -> + view.setOnClickListener( + if (onClicked != null) { + View.OnClickListener { onClicked.invoke() } + } else { + null + } + ) + } + } + } + } + + return DisposableHandle { job.cancel() } + } + + /** + * Uses a "bouncy" animation to animate the selecting or un-selecting of a view with a + * background and a border. + * + * Note that it is expected that the [borderView] is below the [contentView] on the z axis so + * the latter obscures the former at rest. + * + * @param borderView A view for the selection border that should be shown when the view is + * + * ``` + * selected. + * @param contentView + * ``` + * + * The view containing the opaque part of the view. + * + * @param isSelected Whether the view is selected or not. + * @param animationSpec The specification for the animation. + * @param animate Whether to animate; if `false`, will jump directly to the final state without + * + * ``` + * animating. + * ``` + */ + private fun animatedSelection( + borderView: View, + contentView: View, + isSelected: Boolean, + animationSpec: AnimationSpec, + animate: Boolean = true, + ) { + if (isSelected) { + if (!animate) { + borderView.alpha = 1f + borderView.scale(1f) + contentView.scale(0.86f) + return + } + + // Border scale. + borderView + .animate() + .scale(1.099f) + .setDuration(animationSpec.durationMs / 2) + .setInterpolator(PathInterpolator(0.29f, 0f, 0.67f, 1f)) + .withStartAction { + borderView.scaleX = 0.98f + borderView.scaleY = 0.98f + borderView.alpha = 1f + } + .withEndAction { + borderView + .animate() + .scale(1f) + .setDuration(animationSpec.durationMs / 2) + .setInterpolator(PathInterpolator(0.33f, 0f, 0.15f, 1f)) + .start() + } + .start() + + // Background scale. + contentView + .animate() + .scale(0.9321f) + .setDuration(animationSpec.durationMs / 2) + .setInterpolator(PathInterpolator(0.29f, 0f, 0.67f, 1f)) + .withEndAction { + contentView + .animate() + .scale(0.86f) + .setDuration(animationSpec.durationMs / 2) + .setInterpolator(PathInterpolator(0.33f, 0f, 0.15f, 1f)) + .start() + } + .start() + } else { + if (!animate) { + borderView.alpha = 0f + contentView.scale(1f) + return + } + + // Border opacity. + borderView + .animate() + .alpha(0f) + .setDuration(animationSpec.durationMs / 2) + .setInterpolator(LinearInterpolator()) + .start() + + // Border scale. + borderView + .animate() + .scale(1f) + .setDuration(animationSpec.durationMs) + .setInterpolator(PathInterpolator(0.2f, 0f, 0f, 1f)) + .start() + + // Background scale. + contentView + .animate() + .scale(1f) + .setDuration(animationSpec.durationMs) + .setInterpolator(PathInterpolator(0.2f, 0f, 0f, 1f)) + .start() + } + } + + data class AnimationSpec( + /** Opacity of the option when it's enabled. */ + val enabledAlpha: Float = 1f, + /** Opacity of the option when it's disabled. */ + val disabledAlpha: Float = 0.3f, + /** Duration of the animation, in milliseconds. */ + val durationMs: Long = 333L, + ) + + data class TintSpec( + @ColorInt val selectedColor: Int, + @ColorInt val unselectedColor: Int, + ) + + private fun View.scale(scale: Float) { + scaleX = scale + scaleY = scale + } + + private fun ViewPropertyAnimator.scale(scale: Float): ViewPropertyAnimator { + return scaleX(scale).scaleY(scale) + } +} diff --git a/src/com/android/wallpaper/picker/option/ui/viewmodel/OptionItemViewModel.kt b/src/com/android/wallpaper/picker/option/ui/viewmodel/OptionItemViewModel.kt new file mode 100644 index 00000000..61068867 --- /dev/null +++ b/src/com/android/wallpaper/picker/option/ui/viewmodel/OptionItemViewModel.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 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.option.ui.viewmodel + +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +/** Models UI state for an item in a list of selectable options. */ +data class OptionItemViewModel<Payload>( + /** + * A stable key that uniquely identifies this option amongst all other options in the same list + * of options. + */ + val key: StateFlow<String>, + + /** + * The view model representing additional details needed for binding the icon of an option item + */ + val payload: Payload? = null, + + /** + * A text to show to the user (or attach as content description on the icon, if there's no + * dedicated view for it). + */ + val text: Text, + + /** Whether this option is selected. */ + val isSelected: StateFlow<Boolean>, + + /** Whether this option is enabled. */ + val isEnabled: Boolean = true, + + /** Notifies that the option has been clicked by the user. */ + val onClicked: Flow<(() -> Unit)?>, + + /** Notifies that the option has been long-clicked by the user. */ + val onLongClicked: (() -> Unit)? = null, +) { + override fun equals(other: Any?): Boolean { + val otherItem = other as? OptionItemViewModel<*> ?: return false + // skipping comparison of onClicked because it is correlated with + // changes on isSelected + return this.payload == otherItem.payload && + this.text == otherItem.text && + this.isSelected.value == otherItem.isSelected.value && + this.isEnabled == otherItem.isEnabled && + this.onLongClicked == otherItem.onLongClicked + } +} diff --git a/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotRestorer.kt b/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotRestorer.kt index 30478341..27ae6095 100644 --- a/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotRestorer.kt +++ b/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotRestorer.kt @@ -25,12 +25,12 @@ interface SnapshotRestorer { /** * Sets up the restorer. * - * @param updater An updater the can be used when a new snapshot should be stored; invoke this - * in response to state changes that you wish could be restored when the user asks to reset the - * changes. + * @param store An object the can be used when a new snapshot should be stored; use this in + * response to state changes that you wish could be restored when the user asks to reset the + * changes. * @return A snapshot of the initial state as it was at the moment that this method was invoked. */ - suspend fun setUpSnapshotRestorer(updater: (RestorableSnapshot) -> Unit): RestorableSnapshot + suspend fun setUpSnapshotRestorer(store: SnapshotStore): RestorableSnapshot /** Restores the state to what is described in the given snapshot. */ suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) diff --git a/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotStore.kt b/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotStore.kt new file mode 100644 index 00000000..e2906a84 --- /dev/null +++ b/src/com/android/wallpaper/picker/undo/domain/interactor/SnapshotStore.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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.undo.domain.interactor + +import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot + +interface SnapshotStore { + fun retrieve(): RestorableSnapshot + fun store(snapshot: RestorableSnapshot) + + /** A "no op" implementation of [SnapshotStore] that's safe to call. */ + object NOOP : SnapshotStore { + override fun retrieve(): RestorableSnapshot { + return RestorableSnapshot(emptyMap()) + } + + override fun store(snapshot: RestorableSnapshot) = Unit + } +} diff --git a/src/com/android/wallpaper/picker/undo/domain/interactor/UndoInteractor.kt b/src/com/android/wallpaper/picker/undo/domain/interactor/UndoInteractor.kt index 3aa80ae1..53119fd2 100644 --- a/src/com/android/wallpaper/picker/undo/domain/interactor/UndoInteractor.kt +++ b/src/com/android/wallpaper/picker/undo/domain/interactor/UndoInteractor.kt @@ -18,6 +18,7 @@ package com.android.wallpaper.picker.undo.domain.interactor import com.android.wallpaper.picker.undo.data.repository.UndoRepository +import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch @@ -27,14 +28,17 @@ import kotlinx.coroutines.launch * * ## Usage * 1. Instantiate, injecting the supported [SnapshotRestorer] into it, one for each feature that + * * ``` * should support undo functionality. * ``` * 2. Call [startSession] which will bootstrap all passed-in [SnapshotRestorer] instances and + * * ``` * hydrate our model with the latest snapshots from each one. * ``` * 3. Observe [isUndoable] to know whether the UI for triggering an "undo" action should be made + * * ``` * visible to the user. * ``` @@ -51,18 +55,29 @@ class UndoInteractor( /** Bootstraps the undo system, querying each undo-supporting area for the initial snapshot. */ fun startSession() { - // TODO(b/262924056): take in a saved instance state and reuse it instead. repository.clearAllDirty() restorerByOwnerId.forEach { (ownerId, restorer) -> scope.launch { val initialSnapshot = - restorer.setUpSnapshotRestorer { subsequentSnapshot -> - val initialSnapshot = repository.getSnapshot(ownerId) - repository.putDirty( - ownerId = ownerId, - isDirty = initialSnapshot != subsequentSnapshot - ) - } + restorer.setUpSnapshotRestorer( + object : SnapshotStore { + override fun retrieve(): RestorableSnapshot { + return repository.getSnapshot(ownerId) + ?: error( + "No snapshot for this owner ID! Did you call this before" + + " storing a snapshot?" + ) + } + + override fun store(snapshot: RestorableSnapshot) { + val initialSnapshot = repository.getSnapshot(ownerId) + repository.putDirty( + ownerId = ownerId, + isDirty = initialSnapshot != snapshot + ) + } + } + ) repository.putSnapshot( ownerId = ownerId, diff --git a/src/com/android/wallpaper/picker/undo/shared/model/RestorableSnapshot.kt b/src/com/android/wallpaper/picker/undo/shared/model/RestorableSnapshot.kt index aac0e22d..4161a145 100644 --- a/src/com/android/wallpaper/picker/undo/shared/model/RestorableSnapshot.kt +++ b/src/com/android/wallpaper/picker/undo/shared/model/RestorableSnapshot.kt @@ -20,4 +20,33 @@ package com.android.wallpaper.picker.undo.shared.model /** Models a snapshot of the state of an undo-supporting feature at a given time. */ data class RestorableSnapshot( val args: Map<String, String>, -) +) { + /** + * Returns a copy of the [RestorableSnapshot] but with the [block] applied to its arguments. + * + * Sample usage: + * ``` + * val previousSnapshot: RestorableSnapshot = ... + * val nextSnapshot = previousSnapshot { args -> + * args.put("one", "true") + * args.remove("two") + * } + * + * // Now, nextSnapshot is exactly like previousSnapshot but with its args having "one" mapped + * // to "true" and without "two", since it was removed. + * ``` + * + * @param block A function that receives the original [args] from the current + * [RestorableSnapshot] and can edit them for inclusion into the returned + * [RestorableSnapshot]. + */ + fun copy( + block: (MutableMap<String, String>) -> Unit, + ): RestorableSnapshot { + val mutableArgs = args.toMutableMap() + block(mutableArgs) + return RestorableSnapshot( + args = mutableArgs.toMap(), + ) + } +} diff --git a/src/com/android/wallpaper/picker/undo/ui/binder/RevertToolbarButtonBinder.kt b/src/com/android/wallpaper/picker/undo/ui/binder/RevertToolbarButtonBinder.kt index a1eb0185..a2e85ee6 100644 --- a/src/com/android/wallpaper/picker/undo/ui/binder/RevertToolbarButtonBinder.kt +++ b/src/com/android/wallpaper/picker/undo/ui/binder/RevertToolbarButtonBinder.kt @@ -17,7 +17,6 @@ package com.android.wallpaper.picker.undo.ui.binder -import android.app.AlertDialog import android.app.Dialog import android.widget.Toolbar import androidx.lifecycle.Lifecycle @@ -25,7 +24,8 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.wallpaper.R -import com.android.wallpaper.picker.undo.ui.viewmodel.UndoDialogViewModel +import com.android.wallpaper.picker.common.dialog.ui.viewbinder.DialogViewBinder +import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel import com.android.wallpaper.picker.undo.ui.viewmodel.UndoViewModel import kotlinx.coroutines.launch @@ -44,18 +44,12 @@ object RevertToolbarButtonBinder { var dialog: Dialog? = null - fun showDialog(viewModel: UndoDialogViewModel) { + fun showDialog(viewModel: DialogViewModel) { dialog = - AlertDialog.Builder(view.context, R.style.LightDialogTheme) - .setTitle(R.string.reset_confirmation_dialog_title) - .setMessage(R.string.reset_confirmation_dialog_message) - .setPositiveButton(R.string.reset) { _, _ -> viewModel.onConfirmed() } - .setNegativeButton(R.string.cancel, null) - .setOnDismissListener { - dialog = null - viewModel.onDismissed() - } - .create() + DialogViewBinder.show( + context = view.context, + viewModel = viewModel, + ) dialog?.show() } diff --git a/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModel.kt b/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModel.kt index 5e0701bd..37b3e832 100644 --- a/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModel.kt +++ b/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModel.kt @@ -17,6 +17,12 @@ package com.android.wallpaper.picker.undo.ui.viewmodel +import com.android.wallpaper.R +import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonStyle +import com.android.wallpaper.picker.common.button.ui.viewmodel.ButtonViewModel +import com.android.wallpaper.picker.common.dialog.ui.viewmodel.DialogViewModel +import com.android.wallpaper.picker.common.icon.ui.viewmodel.Icon +import com.android.wallpaper.picker.common.text.ui.viewmodel.Text import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -28,21 +34,39 @@ class UndoViewModel( ) { /** Whether the "revert" button should be visible. */ val isRevertButtonVisible: Flow<Boolean> = interactor.isUndoable - private val _dialog = MutableStateFlow<UndoDialogViewModel?>(null) + private val _dialog = MutableStateFlow<DialogViewModel?>(null) /** * A view-model of the undo confirmation dialog that should be shown, or `null` when no dialog * should be shown. */ - val dialog: Flow<UndoDialogViewModel?> = _dialog.asStateFlow() + val dialog: Flow<DialogViewModel?> = _dialog.asStateFlow() /** Notifies that the "revert" button has been clicked by the user. */ fun onRevertButtonClicked() { _dialog.value = - UndoDialogViewModel( - onConfirmed = { - interactor.revertAll() - _dialog.value = null - }, + DialogViewModel( + icon = + Icon.Resource( + res = R.drawable.ic_device_reset, + contentDescription = null, + ), + title = Text.Resource(R.string.reset_confirmation_dialog_title), + message = Text.Resource(R.string.reset_confirmation_dialog_message), + buttons = + listOf( + ButtonViewModel( + text = Text.Resource(R.string.cancel), + style = ButtonStyle.Secondary, + ), + ButtonViewModel( + text = Text.Resource(R.string.reset), + style = ButtonStyle.Primary, + onClicked = { + interactor.revertAll() + _dialog.value = null + }, + ), + ), onDismissed = { _dialog.value = null }, ) } diff --git a/src/com/android/wallpaper/settings/data/repository/SecureSettingsRepository.kt b/src/com/android/wallpaper/settings/data/repository/SecureSettingsRepository.kt new file mode 100644 index 00000000..db56b678 --- /dev/null +++ b/src/com/android/wallpaper/settings/data/repository/SecureSettingsRepository.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 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.settings.data.repository + +import android.content.ContentResolver +import android.database.ContentObserver +import android.provider.Settings +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +/** Defines interface for classes that can provide access to data from [Settings.Secure]. */ +interface SecureSettingsRepository { + + /** Returns a [Flow] tracking the value of a setting as an [Int]. */ + fun intSetting( + name: String, + defaultValue: Int = 0, + ): Flow<Int> + + /** Updates the value of the setting with the given name. */ + suspend fun set( + name: String, + value: Int, + ) + + suspend fun get( + name: String, + defaultValue: Int = 0, + ): Int +} + +class SecureSettingsRepositoryImpl( + private val contentResolver: ContentResolver, + private val backgroundDispatcher: CoroutineDispatcher, +) : SecureSettingsRepository { + + override fun intSetting( + name: String, + defaultValue: Int, + ): Flow<Int> { + return callbackFlow { + val observer = + object : ContentObserver(null) { + override fun onChange(selfChange: Boolean) { + trySend(Unit) + } + } + + contentResolver.registerContentObserver( + Settings.Secure.getUriFor(name), + /* notifyForDescendants= */ false, + observer, + ) + send(Unit) + + awaitClose { contentResolver.unregisterContentObserver(observer) } + } + .map { Settings.Secure.getInt(contentResolver, name, defaultValue) } + // The above work is done on the background thread (which is important for accessing + // settings through the content resolver). + .flowOn(backgroundDispatcher) + } + + override suspend fun set(name: String, value: Int) { + withContext(backgroundDispatcher) { + Settings.Secure.putInt( + contentResolver, + name, + value, + ) + } + } + + override suspend fun get(name: String, defaultValue: Int): Int { + return withContext(backgroundDispatcher) { + Settings.Secure.getInt( + contentResolver, + name, + defaultValue, + ) + } + } +} diff --git a/src/com/android/wallpaper/util/ActivityUtils.java b/src/com/android/wallpaper/util/ActivityUtils.java index 7456edd7..c6ffc61e 100755 --- a/src/com/android/wallpaper/util/ActivityUtils.java +++ b/src/com/android/wallpaper/util/ActivityUtils.java @@ -122,4 +122,13 @@ public final class ActivityUtils { return "wallpaper_only".equals( intent.getStringExtra("com.android.launcher3.WALLPAPER_FLAVOR")); } + + /** + * Returns {@code true} if the activity was launched from the home screen (launcher); + * {@code false} otherwise. + */ + public static boolean isLaunchedFromLauncher(Intent intent) { + return LaunchSourceUtils.LAUNCH_SOURCE_LAUNCHER.equals( + intent.getStringExtra(WALLPAPER_LAUNCH_SOURCE)); + } }
\ No newline at end of file diff --git a/src/com/android/wallpaper/util/DisplayUtils.kt b/src/com/android/wallpaper/util/DisplayUtils.kt index ce6980ed..cd364dbe 100644 --- a/src/com/android/wallpaper/util/DisplayUtils.kt +++ b/src/com/android/wallpaper/util/DisplayUtils.kt @@ -21,49 +21,92 @@ import android.graphics.Point import android.hardware.display.DisplayManager import android.util.Log import android.view.Display +import android.view.Surface.ROTATION_270 +import android.view.Surface.ROTATION_90 /** * Utility class to provide methods to find and obtain information about displays via {@link * DisplayManager} */ -class DisplayUtils(context: Context) { +class DisplayUtils(private val context: Context) { companion object { private const val TAG = "DisplayUtils" + private val ROTATION_HORIZONTAL_HINGE = setOf(ROTATION_90, ROTATION_270) } - private val internalDisplays: List<Display> + private val displayManager: DisplayManager by lazy { + context.applicationContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + } - init { - val appContext = context.applicationContext - val dm = appContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager - val allDisplays: Array<out Display> = - dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED) - if (allDisplays.isEmpty()) { - Log.e(TAG, "No displays found on context $appContext") - throw RuntimeException("No displays found!") - } - internalDisplays = allDisplays.filter { it.type == Display.TYPE_INTERNAL } + fun hasMultiInternalDisplays(): Boolean { + return getInternalDisplays().size > 1 } - /** Returns the {@link Display} to be used to calculate wallpaper size and cropping. */ + /** + * Returns the internal {@link Display} with tthe largest area to be used to calculate wallpaper + * size and cropping. + */ fun getWallpaperDisplay(): Display { - return internalDisplays.maxWithOrNull { a, b -> getRealSize(a) - getRealSize(b) } + val internalDisplays = getInternalDisplays() + return internalDisplays.maxWithOrNull { a, b -> getRealArea(a) - getRealArea(b) } ?: internalDisplays[0] } /** + * Checks if the device only has one display or unfolded screen in horizontal hinge orientation. + */ + fun isSingleDisplayOrUnfoldedHorizontalHinge(activity: Activity): Boolean { + return !hasMultiInternalDisplays() || isUnfoldedHorizontalHinge(activity) + } + + /** + * Checks if the device is a foldable and it's unfolded and in horizontal hinge orientation + * (portrait). + */ + fun isUnfoldedHorizontalHinge(activity: Activity): Boolean { + return activity.display.rotation in ROTATION_HORIZONTAL_HINGE && + isOnWallpaperDisplay(activity) && + hasMultiInternalDisplays() + } + + fun getMaxDisplaysDimension(): Point { + val dimen = Point() + getInternalDisplays().let { displays -> + dimen.x = displays.maxOf { getRealSize(it).x } + dimen.y = displays.maxOf { getRealSize(it).y } + } + return dimen + } + + /** * Returns `true` if the current display is the wallpaper display on a multi-display device. * * On a multi-display device the wallpaper display is the largest display while on a single * display device the only display is both the wallpaper display and the current display. */ fun isOnWallpaperDisplay(activity: Activity): Boolean { - return activity.display.displayId == getWallpaperDisplay().displayId + return activity.display.uniqueId == getWallpaperDisplay().uniqueId } - private fun getRealSize(display: Display): Int { + private fun getRealArea(display: Display): Int { val p = Point() display.getRealSize(p) return p.x * p.y } + + private fun getRealSize(display: Display): Point { + val p = Point() + display.getRealSize(p) + return p + } + + private fun getInternalDisplays(): List<Display> { + val allDisplays: Array<out Display> = + displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED) + if (allDisplays.isEmpty()) { + Log.e(TAG, "No displays found on context ${context.applicationContext}") + throw RuntimeException("No displays found!") + } + return allDisplays.filter { it.type == Display.TYPE_INTERNAL } + } } diff --git a/src/com/android/wallpaper/util/VideoWallpaperUtils.java b/src/com/android/wallpaper/util/VideoWallpaperUtils.java new file mode 100644 index 00000000..2093fe83 --- /dev/null +++ b/src/com/android/wallpaper/util/VideoWallpaperUtils.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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 com.android.wallpaper.model.LiveWallpaperInfo; +import com.android.wallpaper.model.WallpaperInfo; + +/** + * Workarounds for dealing with issues displaying video wallpaper previews until better solutions + * are found. + * + * See b/268066031. + */ +public class VideoWallpaperUtils { + + /** + * Transition time for fade-in animation. + */ + public static final int TRANSITION_MILLIS = 250; + + /** + * Returns true if the is a video wallpaper that requires the fade-in workaround. + */ + public static boolean needsFadeIn(WallpaperInfo info) { + return info instanceof LiveWallpaperInfo; + } +} diff --git a/src/com/android/wallpaper/util/WallpaperCropUtils.java b/src/com/android/wallpaper/util/WallpaperCropUtils.java index 380a6b61..4aed3c2d 100755 --- a/src/com/android/wallpaper/util/WallpaperCropUtils.java +++ b/src/com/android/wallpaper/util/WallpaperCropUtils.java @@ -190,7 +190,8 @@ public final class WallpaperCropUtils { * @return a Rect representing the area of the wallpaper to crop. */ public static Rect calculateCropRect(Context context, float wallpaperZoom, Point wallpaperSize, - Point defaultCropSurfaceSize, Point targetHostSize, int scrollX, int scrollY) { + Point defaultCropSurfaceSize, Point targetHostSize, int scrollX, int scrollY, + boolean cropExtraWidth) { // Calculate Rect of wallpaper in physical pixel terms (i.e., scaled to current zoom). int scaledWallpaperWidth = Math.round(wallpaperSize.x * wallpaperZoom); int scaledWallpaperHeight = Math.round(wallpaperSize.y * wallpaperZoom); @@ -205,12 +206,14 @@ public final class WallpaperCropUtils { int extraWidth = defaultCropSurfaceSize.x - targetHostSize.x; int extraHeightTopAndBottom = (int) ((defaultCropSurfaceSize.y - targetHostSize.y) / 2f); - // Try to increase size of screenRect to include extra width depending on the layout - // direction. - if (isRtl(context)) { - cropRect.left = Math.max(cropRect.left - extraWidth, rect.left); - } else { - cropRect.right = Math.min(cropRect.right + extraWidth, rect.right); + if (cropExtraWidth) { + // Try to increase size of screenRect to include extra width depending on the layout + // direction. + if (isRtl(context)) { + cropRect.left = Math.max(cropRect.left - extraWidth, rect.left); + } else { + cropRect.right = Math.min(cropRect.right + extraWidth, rect.right); + } } // Try to increase the size of the cropRect to to include extra height. @@ -301,14 +304,32 @@ public final class WallpaperCropUtils { * @param rawWallpaperSize the size of the raw wallpaper as a Point (x,y). * @param visibleRawWallpaperRect the area of the raw wallpaper which is expected to see. * @param wallpaperZoom the factor which is used to scale the raw wallpaper. + * @param cropExtraWidth true to crop extra wallpaper width for panel sliding. */ public static Rect calculateCropRect(Context context, Point hostViewSize, Point cropSize, - Point rawWallpaperSize, Rect visibleRawWallpaperRect, float wallpaperZoom) { + Point rawWallpaperSize, Rect visibleRawWallpaperRect, float wallpaperZoom, + boolean cropExtraWidth) { int scrollX = (int) (visibleRawWallpaperRect.left * wallpaperZoom); int scrollY = (int) (visibleRawWallpaperRect.top * wallpaperZoom); return calculateCropRect(context, wallpaperZoom, rawWallpaperSize, cropSize, hostViewSize, - scrollX, scrollY); + scrollX, scrollY, cropExtraWidth); + } + + /** + * Calculates {@link Rect} of the wallpaper which we want to crop to in physical pixel terms + * (i.e., scaled to current zoom). + * + * @param hostViewSize the size of the view hosting the wallpaper as a Point (x,y). + * @param cropSize the default size of the crop as a Point (x,y). + * @param rawWallpaperSize the size of the raw wallpaper as a Point (x,y). + * @param visibleRawWallpaperRect the area of the raw wallpaper which is expected to see. + * @param wallpaperZoom the factor which is used to scale the raw wallpaper. + */ + public static Rect calculateCropRect(Context context, Point hostViewSize, Point cropSize, + Point rawWallpaperSize, Rect visibleRawWallpaperRect, float wallpaperZoom) { + return calculateCropRect(context, hostViewSize, cropSize, rawWallpaperSize, + visibleRawWallpaperRect, wallpaperZoom, /* cropExtraWidth= */ true); } /** diff --git a/src/com/android/wallpaper/widget/DuoTabs.java b/src/com/android/wallpaper/widget/DuoTabs.java index a8f30240..b0fb0b14 100644 --- a/src/com/android/wallpaper/widget/DuoTabs.java +++ b/src/com/android/wallpaper/widget/DuoTabs.java @@ -18,8 +18,8 @@ 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 android.widget.TextView; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -54,10 +54,10 @@ public final class DuoTabs extends FrameLayout { void onTabSelected(@Tab int tab); } - OnTabSelectedListener mOnTabSelectedListener; - Button mPrimaryTab; - Button mSecondaryTab; - @Tab int mCurrentOverlayTab; + private OnTabSelectedListener mOnTabSelectedListener; + private final TextView mPrimaryTab; + private final TextView mSecondaryTab; + @Tab private int mCurrentOverlayTab; /** * Constructor diff --git a/src/com/android/wallpaper/widget/FloatingSheet.kt b/src/com/android/wallpaper/widget/FloatingSheet.kt index 7c8bbd76..26f068a4 100644 --- a/src/com/android/wallpaper/widget/FloatingSheet.kt +++ b/src/com/android/wallpaper/widget/FloatingSheet.kt @@ -154,8 +154,8 @@ class FloatingSheet(context: Context, attrs: AttributeSet?) : FrameLayout(contex * Adds Floating Sheet Callback to connected [BottomSheetBehavior]. * * @param callback the callback for floating sheet state changes, has to be in the type of - * [BottomSheetBehavior.BottomSheetCallback] since the floating sheet behavior is currently - * based on [BottomSheetBehavior] + * [BottomSheetBehavior.BottomSheetCallback] since the floating sheet behavior is currently + * based on [BottomSheetBehavior] */ fun addFloatingSheetCallback(callback: BottomSheetCallback?) { floatingSheetBehavior.addBottomSheetCallback(callback!!) diff --git a/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java b/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java index 00a681ae..c5c8f7ea 100644 --- a/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java +++ b/src/com/android/wallpaper/widget/WallpaperControlButtonGroup.java @@ -35,22 +35,26 @@ import com.android.wallpaper.R; public final class WallpaperControlButtonGroup extends FrameLayout { public static final int DELETE = 0; - public static final int CUSTOMIZE = 1; - public static final int EFFECTS = 2; - public static final int INFORMATION = 3; + public static final int EDIT = 1; + public static final int CUSTOMIZE = 2; + public static final int EFFECTS = 3; + public static final int INFORMATION = 4; + public static final int SHARE = 5; /** * Overlay tab */ - @IntDef({DELETE, CUSTOMIZE, EFFECTS, INFORMATION}) + @IntDef({DELETE, EDIT, CUSTOMIZE, EFFECTS, SHARE, INFORMATION}) public @interface WallpaperControlType { } - final int[] mFloatingSheetControlButtonTypes = { CUSTOMIZE, EFFECTS, INFORMATION }; + final int[] mFloatingSheetControlButtonTypes = { CUSTOMIZE, EFFECTS, SHARE, INFORMATION }; ToggleButton mDeleteButton; + ToggleButton mEditButton; ToggleButton mCustomizeButton; ToggleButton mEffectsButton; + ToggleButton mShareButton; ToggleButton mInformationButton; /** @@ -60,8 +64,10 @@ public final class WallpaperControlButtonGroup extends FrameLayout { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.wallpaper_control_button_group, this, true); mDeleteButton = findViewById(R.id.delete_button); + mEditButton = findViewById(R.id.edit_button); mCustomizeButton = findViewById(R.id.customize_button); mEffectsButton = findViewById(R.id.effects_button); + mShareButton = findViewById(R.id.share_button); mInformationButton = findViewById(R.id.information_button); } @@ -81,10 +87,14 @@ public final class WallpaperControlButtonGroup extends FrameLayout { switch (type) { case DELETE: return mDeleteButton; + case EDIT: + return mEditButton; case CUSTOMIZE: return mCustomizeButton; case EFFECTS: return mEffectsButton; + case SHARE: + return mShareButton; case INFORMATION: return mInformationButton; default: @@ -115,15 +125,21 @@ public final class WallpaperControlButtonGroup extends FrameLayout { return; } mDeleteButton.setForeground(null); + mEditButton.setForeground(null); mCustomizeButton.setForeground(null); mEffectsButton.setForeground(null); + mShareButton.setForeground(null); mInformationButton.setForeground(null); mDeleteButton.setForeground(AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_delete)); + mEditButton.setForeground( + AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_edit)); mCustomizeButton.setForeground(AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_customize)); mEffectsButton.setForeground(AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_effect)); + mShareButton.setForeground(AppCompatResources.getDrawable(context, + R.drawable.wallpaper_control_button_share)); mInformationButton.setForeground( AppCompatResources.getDrawable(context, R.drawable.wallpaper_control_button_info)); } diff --git a/src/com/android/wallpaper/widget/floatingsheetcontent/WallpaperInfoContent.kt b/src/com/android/wallpaper/widget/floatingsheetcontent/WallpaperInfoContent.kt index 2bc75a7a..611df546 100644 --- a/src/com/android/wallpaper/widget/floatingsheetcontent/WallpaperInfoContent.kt +++ b/src/com/android/wallpaper/widget/floatingsheetcontent/WallpaperInfoContent.kt @@ -75,6 +75,8 @@ class WallpaperInfoContent(private var context: Context, private val wallpaper: wallpaper!!, actionLabel, WallpaperInfoHelper.shouldShowExploreButton(context, exploreIntent) - ) { onExploreClicked() } + ) { + onExploreClicked() + } } } diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 5292f000..5715eb7b 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -16,6 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.wallpaper"> + <uses-permission android:name="android.permission.CUSTOMIZE_SYSTEM_UI" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp index 37fb21a9..af260e97 100644 --- a/tests/robotests/Android.bp +++ b/tests/robotests/Android.bp @@ -18,5 +18,7 @@ android_robolectric_test { "androidx.test.runner", ], + upstream: true, + instrumentation_for: "WallpaperPicker2", } diff --git a/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java b/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java index 20ba718d..c3e65646 100644 --- a/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java +++ b/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java @@ -31,7 +31,10 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; +import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -47,6 +50,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; import com.android.wallpaper.R; +import com.android.wallpaper.model.WallpaperInfo; import com.android.wallpaper.module.Injector; import com.android.wallpaper.module.InjectorProvider; import com.android.wallpaper.module.UserEventLogger; @@ -55,9 +59,11 @@ import com.android.wallpaper.module.WallpaperPersister; import com.android.wallpaper.testing.TestAsset; import com.android.wallpaper.testing.TestExploreIntentChecker; import com.android.wallpaper.testing.TestInjector; +import com.android.wallpaper.testing.TestLiveWallpaperInfo; +import com.android.wallpaper.testing.TestStaticWallpaperInfo; import com.android.wallpaper.testing.TestUserEventLogger; -import com.android.wallpaper.testing.TestWallpaperInfo; import com.android.wallpaper.testing.TestWallpaperPersister; +import com.android.wallpaper.testing.TestWallpaperStatusChecker; import com.android.wallpaper.util.ScreenSizeCalculator; import com.android.wallpaper.util.WallpaperCropUtils; @@ -83,11 +89,14 @@ public class PreviewActivityTest { private static final float FLOAT_ERROR_MARGIN = 0.001f; private static final String ACTION_URL = "http://google.com"; - private TestWallpaperInfo mMockWallpaper; + private TestStaticWallpaperInfo mTestStaticWallpaper; + private TestLiveWallpaperInfo mTestLiveWallpaper; private Injector mInjector; private TestWallpaperPersister mWallpaperPersister; private TestUserEventLogger mEventLogger; private TestExploreIntentChecker mExploreIntentChecker; + private TestWallpaperStatusChecker mWallpaperStatusChecker; + private WallpaperManager mWallpaperManager; @Rule public ActivityTestRule<PreviewActivity> mActivityRule = @@ -101,21 +110,30 @@ public class PreviewActivityTest { Intents.init(); - mMockWallpaper = new TestWallpaperInfo(TestWallpaperInfo.COLOR_DEFAULT); List<String> attributions = new ArrayList<>(); attributions.add("Title"); attributions.add("Subtitle 1"); attributions.add("Subtitle 2"); - mMockWallpaper.setAttributions(attributions); - mMockWallpaper.setCollectionId("collection"); - mMockWallpaper.setWallpaperId("wallpaper"); - mMockWallpaper.setActionUrl(ACTION_URL); + mTestStaticWallpaper = new TestStaticWallpaperInfo(TestStaticWallpaperInfo.COLOR_DEFAULT); + mTestStaticWallpaper.setAttributions(attributions); + mTestStaticWallpaper.setCollectionId("collectionStatic"); + mTestStaticWallpaper.setWallpaperId("wallpaperStatic"); + mTestStaticWallpaper.setActionUrl(ACTION_URL); + + mTestLiveWallpaper = new TestLiveWallpaperInfo(TestStaticWallpaperInfo.COLOR_DEFAULT); + mTestLiveWallpaper.setAttributions(attributions); + mTestLiveWallpaper.setCollectionId("collectionLive"); + mTestLiveWallpaper.setWallpaperId("wallpaperLive"); + mTestLiveWallpaper.setActionUrl(ACTION_URL); Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); mWallpaperPersister = (TestWallpaperPersister) mInjector.getWallpaperPersister(context); mEventLogger = (TestUserEventLogger) mInjector.getUserEventLogger(context); mExploreIntentChecker = (TestExploreIntentChecker) mInjector.getExploreIntentChecker(context); + mWallpaperStatusChecker = (TestWallpaperStatusChecker) + mInjector.getWallpaperStatusChecker(); + mWallpaperManager = WallpaperManager.getInstance(context); } @After @@ -124,9 +142,9 @@ public class PreviewActivityTest { mActivityRule.finishActivity(); } - private void launchActivityIntentWithMockWallpaper() { + private void launchActivityIntentWithWallpaper(WallpaperInfo wallpaperInfo) { Intent intent = PreviewActivity.newIntent( - InstrumentationRegistry.getInstrumentation().getTargetContext(), mMockWallpaper); + InstrumentationRegistry.getInstrumentation().getTargetContext(), wallpaperInfo); intent.putExtra(BasePreviewActivity.EXTRA_TESTING_MODE_ENABLED, true); mActivityRule.launchActivity(intent); @@ -164,13 +182,13 @@ public class PreviewActivityTest { @Test public void testRendersWallpaperDrawableFromIntent() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertTrue(getFullResImageView(mActivityRule.getActivity()).hasImage()); } @Test public void testClickSetWallpaper_Success_HomeScreen() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentHomeWallpaper()); onView(withId(R.id.action_apply)).perform(click()); @@ -183,7 +201,7 @@ public class PreviewActivityTest { finishSettingWallpaperThenDo(() -> { // Mock system wallpaper bitmap should be equal to the mock WallpaperInfo's bitmap. Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper())); // The wallpaper should have been set on the home screen. @@ -199,7 +217,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_Success_LockScreen() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentLockWallpaper()); onView(withId(R.id.action_apply)).perform(click()); @@ -212,7 +230,7 @@ public class PreviewActivityTest { finishSettingWallpaperThenDo(() -> { // Mock system wallpaper bitmap should be equal to the mock WallpaperInfo's bitmap. Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper())); // The wallpaper should have been set on the lock screen. @@ -228,7 +246,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_Success_BothHomeAndLockScreen() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentHomeWallpaper()); assertNull(mWallpaperPersister.getCurrentLockWallpaper()); @@ -243,7 +261,7 @@ public class PreviewActivityTest { finishSettingWallpaperThenDo(() -> { // Mock system wallpaper bitmap should be equal to the mock WallpaperInfo's bitmap. Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper())); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper())); @@ -259,7 +277,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_Fails_HomeScreen_ShowsErrorDialog() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentHomeWallpaper()); mWallpaperPersister.setFailNextCall(true); @@ -285,7 +303,7 @@ public class PreviewActivityTest { finishSettingWallpaperThenDo(() -> { assertNotNull(mWallpaperPersister.getCurrentHomeWallpaper()); Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper())); // The wallpaper should have been set on the home screen. @@ -297,7 +315,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_Fails_LockScreen_ShowsErrorDialog() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentLockWallpaper()); mWallpaperPersister.setFailNextCall(true); @@ -327,7 +345,7 @@ public class PreviewActivityTest { Bitmap newBitmap = mWallpaperPersister.getCurrentLockWallpaper(); assertNotNull(newBitmap); Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(newBitmap)); // The wallpaper should have been set on the lock screen. @@ -339,7 +357,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_Fails_BothHomeAndLock_ShowsErrorDialog() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); assertNull(mWallpaperPersister.getCurrentHomeWallpaper()); assertNull(mWallpaperPersister.getCurrentLockWallpaper()); @@ -368,7 +386,7 @@ public class PreviewActivityTest { assertNotNull(mWallpaperPersister.getCurrentHomeWallpaper()); assertNotNull(mWallpaperPersister.getCurrentLockWallpaper()); Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap(); + Bitmap srcBitmap = ((TestAsset) mTestStaticWallpaper.getAsset(context)).getBitmap(); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper())); assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper())); @@ -382,7 +400,7 @@ public class PreviewActivityTest { @Test @Ignore("b/248538709") public void testClickSetWallpaper_CropsAndScalesWallpaper() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); // Scale should not have a meaningful value before clicking "set wallpaper". assertTrue(mWallpaperPersister.getScale() < 0); @@ -410,7 +428,7 @@ public class PreviewActivityTest { @Test public void testClickSetWallpaper_FailsCroppingAndScalingWallpaper_ShowsErrorDialog() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); mWallpaperPersister.setFailNextCall(true); onView(withId(R.id.action_apply)).perform(click()); // Destination dialog is shown; click "Home screen". @@ -427,19 +445,45 @@ public class PreviewActivityTest { */ @Test public void testClickSetWallpaper_ShowsDestinationDialog() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); onView(withId(R.id.action_apply)).perform(click()); onView(withText(R.string.set_wallpaper_dialog_message)).check(matches(isDisplayed())); } @Test + public void testDestinationOptions_singleEngine_setLive_doesNotShowLockOption() { + assumeFalse(mWallpaperManager.isLockscreenLiveWallpaperEnabled()); + launchActivityIntentWithWallpaper(mTestLiveWallpaper); + mWallpaperStatusChecker.setHomeStaticWallpaperSet(true); + mWallpaperStatusChecker.setLockWallpaperSet(false); + + onView(withId(R.id.action_apply)).perform(click()); + + onView(withText(R.string.set_wallpaper_lock_screen_destination)).inRoot(isDialog()) + .check(matches(not(isDisplayed()))); + } + + @Test + public void testDestinationOptions_multiEngine_setLive_showsLockOption() { + assumeTrue(mWallpaperManager.isLockscreenLiveWallpaperEnabled()); + launchActivityIntentWithWallpaper(mTestLiveWallpaper); + mWallpaperStatusChecker.setHomeStaticWallpaperSet(true); + mWallpaperStatusChecker.setLockWallpaperSet(false); + + onView(withId(R.id.action_apply)).perform(click()); + + onView(withText(R.string.set_wallpaper_lock_screen_destination)).inRoot(isDialog()) + .check(matches(isDisplayed())); + } + + @Test @Ignore("b/248538709") public void testSetsDefaultWallpaperZoomAndScroll() { float expectedWallpaperZoom; int expectedWallpaperScrollX; int expectedWallpaperScrollY; - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); PreviewActivity activity = mActivityRule.getActivity(); SubsamplingScaleImageView fullResImageView = getFullResImageView(activity); @@ -447,7 +491,7 @@ public class PreviewActivityTest { activity.getResources(), activity.getWindowManager().getDefaultDisplay()); Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize( activity.getWindowManager().getDefaultDisplay()); - TestAsset asset = (TestAsset) mMockWallpaper.getAsset(activity); + TestAsset asset = (TestAsset) mTestStaticWallpaper.getAsset(activity); Point wallpaperSize = new Point(asset.getBitmap().getWidth(), asset.getBitmap().getHeight()); @@ -479,7 +523,7 @@ public class PreviewActivityTest { @Test public void testShowSetWallpaperDialog_TemporarilyLocksScreenOrientation() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); PreviewActivity activity = mActivityRule.getActivity(); assertNotEquals(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activity.getRequestedOrientation()); @@ -496,7 +540,7 @@ public class PreviewActivityTest { @Test public void testSetWallpaper_TemporarilyLocksScreenOrientation() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); PreviewActivity activity = mActivityRule.getActivity(); assertNotEquals(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activity.getRequestedOrientation()); @@ -515,7 +559,7 @@ public class PreviewActivityTest { @Test public void testShowsWallpaperAttribution() { - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); PreviewActivity activity = mActivityRule.getActivity(); TextView titleView = activity.findViewById(R.id.wallpaper_info_title); @@ -535,8 +579,8 @@ public class PreviewActivityTest { @Test public void testLoadWallpaper_Failed_ShowsErrorDialog() { // Simulate a corrupted asset that fails to perform decoding operations. - mMockWallpaper.corruptAssets(); - launchActivityIntentWithMockWallpaper(); + mTestStaticWallpaper.corruptAssets(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); onView(withText(R.string.load_wallpaper_error_message)).inRoot(isDialog()).check( matches(isDisplayed())); @@ -554,7 +598,7 @@ public class PreviewActivityTest { public void testNoActionViewHandler_ExploreButtonNotVisible() { mExploreIntentChecker.setViewHandlerExists(false); - launchActivityIntentWithMockWallpaper(); + launchActivityIntentWithWallpaper(mTestStaticWallpaper); onView(withId(R.id.wallpaper_info_explore_button)).check( matches(not(isDisplayed()))); } diff --git a/tests/src/com/android/wallpaper/picker/customization/data/content/FakeWallpaperClient.kt b/tests/src/com/android/wallpaper/picker/customization/data/content/FakeWallpaperClient.kt new file mode 100644 index 00000000..4930418b --- /dev/null +++ b/tests/src/com/android/wallpaper/picker/customization/data/content/FakeWallpaperClient.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2023 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.customization.data.content + +import android.graphics.Bitmap +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import kotlin.math.min +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map + +class FakeWallpaperClient : WallpaperClient { + + private val _recentWallpapers = + MutableStateFlow( + buildMap { + WallpaperDestination.values() + .filter { it != WallpaperDestination.BOTH } + .forEach { screen -> put(screen, INITIAL_RECENT_WALLPAPERS) } + } + ) + private var isPaused = false + private var deferred = mutableListOf<(suspend () -> Unit)>() + + fun setRecentWallpapers( + recentWallpapersByDestination: Map<WallpaperDestination, List<WallpaperModel>>, + ) { + _recentWallpapers.value = recentWallpapersByDestination + } + + fun pause() { + isPaused = true + } + + suspend fun unpause() { + isPaused = false + deferred.forEach { it.invoke() } + deferred.clear() + } + + override fun recentWallpapers( + destination: WallpaperDestination, + limit: Int, + ): Flow<List<WallpaperModel>> { + return _recentWallpapers.map { wallpapersByScreen -> + val wallpapers = + wallpapersByScreen[destination] ?: error("No wallpapers for screen $destination") + if (wallpapers.size > limit) { + wallpapers.subList(0, min(limit, wallpapers.size)) + } else { + wallpapers + } + } + } + + override suspend fun getCurrentWallpaper( + destination: WallpaperDestination, + ): WallpaperModel { + return _recentWallpapers.value[destination]?.get(0) + ?: error("No wallpapers for screen $destination") + } + + override suspend fun setWallpaper( + destination: WallpaperDestination, + wallpaperId: String, + onDone: () -> Unit + ) { + if (isPaused) { + deferred.add { setWallpaper(destination, wallpaperId, onDone) } + } else { + _recentWallpapers.value = + _recentWallpapers.value.toMutableMap().apply { + this[destination] = + _recentWallpapers.value[destination]?.sortedBy { + it.wallpaperId != wallpaperId + } + ?: error("No wallpapers for screen $destination") + } + onDone.invoke() + } + } + + override suspend fun loadThumbnail(wallpaperId: String): Bitmap? { + return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) + } + + companion object { + val INITIAL_RECENT_WALLPAPERS = + listOf( + WallpaperModel( + wallpaperId = "zero", + placeholderColor = 0, + ), + WallpaperModel( + wallpaperId = "one", + placeholderColor = 1, + ), + WallpaperModel( + wallpaperId = "two", + placeholderColor = 2, + ), + ) + } +} diff --git a/tests/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepositoryTest.kt b/tests/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepositoryTest.kt new file mode 100644 index 00000000..7e2c64b3 --- /dev/null +++ b/tests/src/com/android/wallpaper/picker/customization/data/repository/WallpaperRepositoryTest.kt @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2023 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.customization.data.repository + +import androidx.test.filters.SmallTest +import com.android.wallpaper.picker.customization.data.content.FakeWallpaperClient +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.testing.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class WallpaperRepositoryTest { + + private lateinit var underTest: WallpaperRepository + + private lateinit var client: FakeWallpaperClient + private lateinit var testScope: TestScope + + @Before + fun setUp() { + client = FakeWallpaperClient() + + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + underTest = + WallpaperRepository( + scope = testScope.backgroundScope, + client = client, + backgroundDispatcher = testDispatcher, + ) + } + + @Test + fun setWallpaper() = + testScope.runTest { + val recentHomeWallpapers = + collectLastValue( + underTest.recentWallpapers(destination = WallpaperDestination.HOME, limit = 5) + ) + val recentLockWallpapers = + collectLastValue( + underTest.recentWallpapers(destination = WallpaperDestination.LOCK, limit = 5) + ) + val selectedHomeWallpaperId = + collectLastValue(underTest.selectedWallpaperId(WallpaperDestination.HOME)) + val selectedLockWallpaperId = + collectLastValue(underTest.selectedWallpaperId(WallpaperDestination.LOCK)) + val selectingHomeWallpaperId = + collectLastValue( + underTest.selectingWallpaperId.map { it[WallpaperDestination.HOME] } + ) + val selectingLockWallpaperId = + collectLastValue( + underTest.selectingWallpaperId.map { it[WallpaperDestination.LOCK] } + ) + assertThat(recentHomeWallpapers()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(recentLockWallpapers()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(selectedHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.first().wallpaperId) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.first().wallpaperId) + assertThat(selectingHomeWallpaperId()).isNull() + assertThat(selectingLockWallpaperId()).isNull() + + // Pause the client so we can examine the interim state. + client.pause() + underTest.setWallpaper( + WallpaperDestination.HOME, + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId, + ) + underTest.setWallpaper( + WallpaperDestination.LOCK, + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId, + ) + assertThat(recentHomeWallpapers()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(recentLockWallpapers()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(selectedHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.first().wallpaperId) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.first().wallpaperId) + assertThat(selectingHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId) + assertThat(selectingLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId) + + // Unpause the client so we can examine the final state. + client.unpause() + assertThat(recentHomeWallpapers()) + .isEqualTo( + listOf( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2], + ) + ) + assertThat(recentLockWallpapers()) + .isEqualTo( + listOf( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1], + ) + ) + assertThat(selectedHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId) + assertThat(selectingHomeWallpaperId()).isNull() + assertThat(selectingLockWallpaperId()).isNull() + } +} diff --git a/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractorTest.kt b/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractorTest.kt new file mode 100644 index 00000000..1686c536 --- /dev/null +++ b/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperInteractorTest.kt @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2023 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.customization.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.customization.data.content.FakeWallpaperClient +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.testing.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class WallpaperInteractorTest { + + private lateinit var underTest: WallpaperInteractor + + private lateinit var client: FakeWallpaperClient + private lateinit var testScope: TestScope + + @Before + fun setUp() { + client = FakeWallpaperClient() + + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + underTest = + WallpaperInteractor( + repository = + WallpaperRepository( + scope = testScope.backgroundScope, + client = client, + backgroundDispatcher = testDispatcher, + ), + ) + } + + @Test + fun `previews - limits to maximum results`() = + testScope.runTest { + val limited = + collectLastValue( + underTest.previews( + destination = WallpaperDestination.HOME, + maxResults = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.size - 1 + ) + ) + + assertThat(limited()) + .isEqualTo( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.subList( + 0, + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.size - 1, + ) + ) + } + + @Test + fun wallpaperUpdateEvents() = + testScope.runTest { + val homeWallpaperUpdateEvents = + collectLastValue( + underTest.wallpaperUpdateEvents(CustomizationSections.Screen.HOME_SCREEN) + ) + val lockWallpaperUpdateEvents = + collectLastValue( + underTest.wallpaperUpdateEvents(CustomizationSections.Screen.LOCK_SCREEN) + ) + val homeWallpaperUpdateOutput1 = homeWallpaperUpdateEvents() + val lockWallpaperUpdateOutput1 = lockWallpaperUpdateEvents() + + val homeWallpaperId1 = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId + val lockWallpaperId1 = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId + underTest.setWallpaper(WallpaperDestination.HOME, homeWallpaperId1) + underTest.setWallpaper(WallpaperDestination.LOCK, lockWallpaperId1) + assertThat(homeWallpaperUpdateEvents()).isNotEqualTo(homeWallpaperUpdateOutput1) + assertThat(lockWallpaperUpdateEvents()).isNotEqualTo(lockWallpaperUpdateOutput1) + val homeWallpaperUpdateOutput2 = homeWallpaperUpdateEvents() + val lockWallpaperUpdateOutput2 = lockWallpaperUpdateEvents() + + val homeWallpaperId2 = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId + val lockWallpaperId2 = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId + underTest.setWallpaper(WallpaperDestination.HOME, homeWallpaperId2) + underTest.setWallpaper(WallpaperDestination.LOCK, lockWallpaperId2) + assertThat(homeWallpaperUpdateEvents()).isNotEqualTo(homeWallpaperUpdateOutput2) + assertThat(lockWallpaperUpdateEvents()).isEqualTo(lockWallpaperUpdateOutput2) + } + + @Test + fun setWallpaper() = + testScope.runTest { + val homePreviews = + collectLastValue( + underTest.previews( + destination = WallpaperDestination.HOME, + maxResults = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.size + ) + ) + val lockPreviews = + collectLastValue( + underTest.previews( + destination = WallpaperDestination.LOCK, + maxResults = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.size + ) + ) + val selectedHomeWallpaperId = + collectLastValue(underTest.selectedWallpaperId(WallpaperDestination.HOME)) + val selectedLockWallpaperId = + collectLastValue(underTest.selectedWallpaperId(WallpaperDestination.LOCK)) + val selectingHomeWallpaperId = + collectLastValue(underTest.selectingWallpaperId(WallpaperDestination.HOME)) + val selectingLockWallpaperId = + collectLastValue(underTest.selectingWallpaperId(WallpaperDestination.LOCK)) + assertThat(homePreviews()).isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(lockPreviews()).isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0].wallpaperId) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0].wallpaperId) + assertThat(selectingHomeWallpaperId()).isNull() + assertThat(selectingLockWallpaperId()).isNull() + val homeWallpaperId = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId + val lockWallpaperId = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId + + // Pause the client so we can examine the interim state. + client.pause() + underTest.setWallpaper(WallpaperDestination.HOME, homeWallpaperId) + underTest.setWallpaper(WallpaperDestination.LOCK, lockWallpaperId) + assertThat(homePreviews()).isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(lockPreviews()).isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS) + assertThat(selectedHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0].wallpaperId) + assertThat(selectedLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0].wallpaperId) + assertThat(selectingHomeWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1].wallpaperId) + assertThat(selectingLockWallpaperId()) + .isEqualTo(FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2].wallpaperId) + + // Unpause the client so we can examine the final state. + client.unpause() + assertThat(homePreviews()) + .isEqualTo( + listOf( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2], + ) + ) + assertThat(lockPreviews()) + .isEqualTo( + listOf( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1], + ) + ) + assertThat(selectedHomeWallpaperId()).isEqualTo(homeWallpaperId) + assertThat(selectedLockWallpaperId()).isEqualTo(lockWallpaperId) + assertThat(selectingHomeWallpaperId()).isNull() + assertThat(selectingLockWallpaperId()).isNull() + } +} diff --git a/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorerTest.kt b/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorerTest.kt new file mode 100644 index 00000000..3126d3d3 --- /dev/null +++ b/tests/src/com/android/wallpaper/picker/customization/domain/interactor/WallpaperSnapshotRestorerTest.kt @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 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.customization.domain.interactor + +import android.util.Log +import androidx.test.filters.SmallTest +import com.android.wallpaper.picker.customization.data.content.FakeWallpaperClient +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore +import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class WallpaperSnapshotRestorerTest { + + private lateinit var underTest: WallpaperSnapshotRestorer + private lateinit var testScope: TestScope + private lateinit var wallpaperClient: FakeWallpaperClient + private lateinit var store: SnapshotStore + private lateinit var storedSnapshots: MutableList<RestorableSnapshot> + + @Before + fun setUp() { + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + wallpaperClient = FakeWallpaperClient() + storedSnapshots = mutableListOf() + store = + object : SnapshotStore { + override fun store(snapshot: RestorableSnapshot) { + Log.d("ALE", "storing snapshot #${storedSnapshots.size + 1}") + storedSnapshots.add(snapshot) + } + + override fun retrieve(): RestorableSnapshot { + return storedSnapshots.last() + } + } + + underTest = + WallpaperSnapshotRestorer( + scope = testScope.backgroundScope, + interactor = + WallpaperInteractor( + repository = + WallpaperRepository( + scope = testScope.backgroundScope, + client = wallpaperClient, + backgroundDispatcher = testDispatcher, + ), + ) + ) + } + + @Test + fun restore() = + testScope.runTest { + wallpaperClient.setRecentWallpapers( + buildMap { + put(WallpaperDestination.HOME, INITIAL_HOME_WALLPAPERS) + put(WallpaperDestination.LOCK, INITIAL_LOCK_WALLPAPERS) + } + ) + val initialSnapshot = underTest.setUpSnapshotRestorer(store) + runCurrent() + wallpaperClient.setWallpaper( + destination = WallpaperDestination.HOME, + wallpaperId = INITIAL_HOME_WALLPAPERS[1].wallpaperId, + onDone = {}, + ) + runCurrent() + assertThat(storedSnapshots).hasSize(1) + wallpaperClient.setWallpaper( + destination = WallpaperDestination.LOCK, + wallpaperId = INITIAL_LOCK_WALLPAPERS[4].wallpaperId, + onDone = {}, + ) + runCurrent() + assertThat(storedSnapshots).hasSize(2) + + underTest.restoreToSnapshot(storedSnapshots[0]) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.HOME)) + .isEqualTo(INITIAL_HOME_WALLPAPERS[1]) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.LOCK)) + .isEqualTo(INITIAL_LOCK_WALLPAPERS[0]) + + underTest.restoreToSnapshot(initialSnapshot) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.HOME)) + .isEqualTo(INITIAL_HOME_WALLPAPERS[0]) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.LOCK)) + .isEqualTo(INITIAL_LOCK_WALLPAPERS[0]) + + underTest.restoreToSnapshot(storedSnapshots[1]) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.HOME)) + .isEqualTo(INITIAL_HOME_WALLPAPERS[1]) + assertThat(wallpaperClient.getCurrentWallpaper(destination = WallpaperDestination.LOCK)) + .isEqualTo(INITIAL_LOCK_WALLPAPERS[4]) + } + + companion object { + private val INITIAL_HOME_WALLPAPERS = + (0..5).map { index -> WallpaperModel(wallpaperId = "H$index", placeholderColor = 0) } + private val INITIAL_LOCK_WALLPAPERS = + (0..5).map { index -> WallpaperModel(wallpaperId = "L$index", placeholderColor = 0) } + } +} diff --git a/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModelTest.kt b/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModelTest.kt index f9c06405..5e74accb 100644 --- a/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModelTest.kt +++ b/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/CustomizationPickerViewModelTest.kt @@ -76,6 +76,40 @@ class CustomizationPickerViewModelTest { } @Test + fun `setInitialScreen - home screen`() = + testScope.runTest { + underTest.setInitialScreen(onLockScreen = false) + + val homeScreenTab = collectLastValue(underTest.homeScreenTab) + val lockScreenTab = collectLastValue(underTest.lockScreenTab) + val isOnLockScreen = collectLastValue(underTest.isOnLockScreen) + + assertThat(homeScreenTab()?.isSelected).isTrue() + assertThat(lockScreenTab()?.isSelected).isFalse() + assertThat(isOnLockScreen()).isFalse() + } + + @Test + fun `setInitialScreen - home screen - but lock screen already selected from before`() = + testScope.runTest { + // First, we start on the Home screen. + underTest.setInitialScreen(onLockScreen = false) + // Then, we switch to the lock screen. + collectLastValue(underTest.lockScreenTab)()?.onClicked?.invoke() + // Instantiate a new view-model with the same saved state. + val newUnderTest = + CustomizationPickerViewModel( + undoInteractor = undoInteractor, + savedStateHandle = savedStateHandle, + ) + val newIsOnLockScreen = collectLastValue(newUnderTest.isOnLockScreen) + + newUnderTest.setInitialScreen(onLockScreen = false) + + assertThat(newIsOnLockScreen()).isTrue() + } + + @Test fun `switching to the home screen`() = testScope.runTest { val homeScreenTab = collectLastValue(underTest.homeScreenTab) diff --git a/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModelTest.kt b/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModelTest.kt new file mode 100644 index 00000000..b22002c0 --- /dev/null +++ b/tests/src/com/android/wallpaper/picker/customization/ui/viewmodel/WallpaperQuickSwitchViewModelTest.kt @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2023 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.customization.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.wallpaper.picker.customization.data.content.FakeWallpaperClient +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.shared.model.WallpaperDestination +import com.android.wallpaper.picker.customization.shared.model.WallpaperModel +import com.android.wallpaper.testing.collectLastValue +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class WallpaperQuickSwitchViewModelTest { + + private lateinit var underTest: WallpaperQuickSwitchViewModel + + private lateinit var client: FakeWallpaperClient + private lateinit var testScope: TestScope + + @Before + fun setUp() { + client = FakeWallpaperClient() + + val testDispatcher = StandardTestDispatcher() + Dispatchers.setMain(testDispatcher) + testScope = TestScope(testDispatcher) + val interactor = + WallpaperInteractor( + repository = + WallpaperRepository( + scope = testScope.backgroundScope, + client = client, + backgroundDispatcher = testDispatcher, + ), + ) + underTest = + WallpaperQuickSwitchViewModel( + interactor = interactor, + maxOptions = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS.size, + ) + } + + @After + fun tearDown() { + Dispatchers.resetMain() + } + + @Test + fun `initial options`() = + testScope.runTest { + val options = collectLastValue(underTest.options) + assertOptions( + observed = options(), + expected = expectations(), + ) + } + + @Test + fun `updates options`() = + testScope.runTest { + val options = collectLastValue(underTest.options) + + val models = + listOf( + WallpaperModel( + wallpaperId = "aaa", + placeholderColor = 1200, + ), + WallpaperModel( + wallpaperId = "bbb", + placeholderColor = 1300, + ), + WallpaperModel( + wallpaperId = "ccc", + placeholderColor = 1400, + ), + ) + client.setRecentWallpapers(buildMap { put(WallpaperDestination.HOME, models) }) + + assertOptions( + observed = options(), + expected = + expectations( + models = models, + ), + ) + } + + @Test + fun `switches to third option`() = + testScope.runTest { + val options = collectLastValue(underTest.options) + + // Pause the client so we can examine the interim state. + client.pause() + val selectedIndex = 2 + val optionToSelect = checkNotNull(options()?.get(selectedIndex)) + val onSelected = collectLastValue(optionToSelect.onSelected) + onSelected()?.invoke() + + assertOptions( + observed = options(), + expected = + expectations( + selectingIndex = selectedIndex, + ), + ) + + // Unpause the client so we can examine the final state. + client.unpause() + runCurrent() + assertOptions( + observed = options(), + expected = + expectations( + selectedIndex = selectedIndex, + ), + ) + } + + @Test + fun `switches between screens`() = + testScope.runTest { + val options = collectLastValue(underTest.options) + + // We begin on the home screen by default. + // Select option at index 2 on the home screen. + val selectedIndex = 2 + val optionToSelect = checkNotNull(options()?.get(selectedIndex)) + val onSelected = collectLastValue(optionToSelect.onSelected) + onSelected()?.invoke() + runCurrent() + assertOptions( + observed = options(), + expected = + expectations( + selectedIndex = selectedIndex, + ), + ) + + // Switch to the lock screen, it should still have the original option selected. + underTest.setOnLockScreen(isLockScreenSelected = true) + runCurrent() + assertOptions( + observed = options(), + expected = expectations(), + ) + + // Switch back to the home screen, it should still have option at index 2 selected. + underTest.setOnLockScreen(isLockScreenSelected = false) + runCurrent() + assertOptions( + observed = options(), + expected = + expectations( + models = + listOf( + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[2], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[0], + FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS[1], + ), + ), + ) + } + + private fun expectations( + models: List<WallpaperModel> = FakeWallpaperClient.INITIAL_RECENT_WALLPAPERS, + selectedIndex: Int = 0, + selectingIndex: Int? = null, + ): List<ExpectedOption> { + return models.mapIndexed { index, model -> + val nothingBeingSelected = selectingIndex == null + val isBeingSelected = selectingIndex == index + val isSelected = selectedIndex == index + ExpectedOption( + wallpaperId = model.wallpaperId, + placeholderColor = model.placeholderColor, + isLarge = isBeingSelected || (nothingBeingSelected && isSelected), + isSelectionIconVisible = nothingBeingSelected && isSelected, + isSelectionBorderVisible = isBeingSelected || (nothingBeingSelected && isSelected), + isProgressIndicatorVisible = isBeingSelected, + isSelectable = + (!nothingBeingSelected && !isBeingSelected) || + (nothingBeingSelected && !isSelected), + ) + } + } + + private fun TestScope.assertOptions( + observed: List<WallpaperQuickSwitchOptionViewModel>?, + expected: List<ExpectedOption>, + ) { + checkNotNull(observed) + assertThat(observed).hasSize(expected.size) + observed.forEachIndexed { index, option -> + assertWithMessage("mismatching wallpaperId for index $index.") + .that(option.wallpaperId) + .isEqualTo(expected[index].wallpaperId) + assertWithMessage("mismatching isLarge for index $index.") + .that(collectLastValue(option.isLarge)()) + .isEqualTo(expected[index].isLarge) + assertWithMessage("mismatching placeholderColor for index $index.") + .that(option.placeholderColor) + .isEqualTo(expected[index].placeholderColor) + assertWithMessage("mismatching isProgressIndicatorVisible for index $index.") + .that(collectLastValue(option.isProgressIndicatorVisible)()) + .isEqualTo(expected[index].isProgressIndicatorVisible) + assertWithMessage("mismatching isSelectionIconVisible for index $index.") + .that(collectLastValue(option.isSelectionIconVisible)()) + .isEqualTo(expected[index].isSelectionIconVisible) + assertWithMessage("mismatching isSelectionBorderVisible for index $index.") + .that(collectLastValue(option.isSelectionBorderVisible)()) + .isEqualTo(expected[index].isSelectionBorderVisible) + assertWithMessage("mismatching isSelectable for index $index.") + .that(collectLastValue(option.onSelected)() != null) + .isEqualTo(expected[index].isSelectable) + } + } + + private data class ExpectedOption( + val wallpaperId: String, + val placeholderColor: Int, + val isLarge: Boolean = false, + val isProgressIndicatorVisible: Boolean = false, + val isSelectionIconVisible: Boolean = false, + val isSelectionBorderVisible: Boolean = false, + val isSelectable: Boolean = true, + ) +} diff --git a/tests/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModelTest.kt b/tests/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModelTest.kt index 0def5f29..a2da80fd 100644 --- a/tests/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModelTest.kt +++ b/tests/src/com/android/wallpaper/picker/undo/ui/viewmodel/UndoViewModelTest.kt @@ -93,7 +93,7 @@ class UndoViewModelTest { assertThat(dialog()).isNotNull() // Confirm the revert. - dialog()?.onConfirmed?.invoke() + dialog()?.buttons?.last()?.onClicked?.invoke() assertThat(isRevertButtonVisible()).isFalse() } } diff --git a/tests/src/com/android/wallpaper/testing/FakeSecureSettingsRepository.kt b/tests/src/com/android/wallpaper/testing/FakeSecureSettingsRepository.kt new file mode 100644 index 00000000..7855a366 --- /dev/null +++ b/tests/src/com/android/wallpaper/testing/FakeSecureSettingsRepository.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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.testing + +import com.android.wallpaper.settings.data.repository.SecureSettingsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map + +class FakeSecureSettingsRepository : SecureSettingsRepository { + + private val settings = MutableStateFlow<Map<String, String>>(mutableMapOf()) + + override fun intSetting(name: String, defaultValue: Int): Flow<Int> { + return settings.map { it.getOrDefault(name, defaultValue.toString()) }.map { it.toInt() } + } + + override suspend fun set(name: String, value: Int) { + settings.value = settings.value.toMutableMap().apply { this[name] = value.toString() } + } + + override suspend fun get(name: String, defaultValue: Int): Int { + return settings.value[name]?.toInt() ?: defaultValue + } +} diff --git a/tests/src/com/android/wallpaper/testing/FakeSnapshotStore.kt b/tests/src/com/android/wallpaper/testing/FakeSnapshotStore.kt new file mode 100644 index 00000000..a2a8b7c6 --- /dev/null +++ b/tests/src/com/android/wallpaper/testing/FakeSnapshotStore.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 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.testing + +import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore +import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot + +class FakeSnapshotStore( + initialSnapshot: RestorableSnapshot = RestorableSnapshot(emptyMap()), +) : SnapshotStore { + private var snapshot = initialSnapshot + + override fun retrieve(): RestorableSnapshot { + return snapshot + } + + override fun store(snapshot: RestorableSnapshot) { + this.snapshot = snapshot + } +} diff --git a/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java b/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java index d6fa9792..e93c089b 100644 --- a/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java +++ b/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java @@ -39,7 +39,7 @@ public class TestCategoryProvider implements CategoryProvider { 0 /* priority */); ArrayList<WallpaperInfo> wallpapers = new ArrayList<>(); - WallpaperInfo wallpaperInfo = new com.android.wallpaper.testing.TestWallpaperInfo(0); + WallpaperInfo wallpaperInfo = new TestStaticWallpaperInfo(0); wallpapers.add(wallpaperInfo); Category category2 = new com.android.wallpaper.testing.TestWallpaperCategory( "Test category", "init_collection", wallpapers, diff --git a/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java b/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java index 8d4b929a..8773b088 100644 --- a/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java +++ b/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java @@ -61,7 +61,8 @@ public class TestCurrentWallpaperInfoFactory implements CurrentWallpaperInfoFact private static WallpaperInfo createTestWallpaperInfo(List<String> attributions, String actionUrl, String collectionId) { - TestWallpaperInfo wallpaper = new TestWallpaperInfo(TestWallpaperInfo.COLOR_DEFAULT); + TestStaticWallpaperInfo wallpaper = new TestStaticWallpaperInfo( + TestStaticWallpaperInfo.COLOR_DEFAULT); wallpaper.setAttributions(attributions); wallpaper.setActionUrl(actionUrl); wallpaper.setCollectionId(collectionId); diff --git a/tests/src/com/android/wallpaper/testing/TestCustomizationSections.kt b/tests/src/com/android/wallpaper/testing/TestCustomizationSections.kt index 0c0ac2ee..d66306ac 100644 --- a/tests/src/com/android/wallpaper/testing/TestCustomizationSections.kt +++ b/tests/src/com/android/wallpaper/testing/TestCustomizationSections.kt @@ -7,26 +7,28 @@ import com.android.wallpaper.model.CustomizationSectionController import com.android.wallpaper.model.PermissionRequester import com.android.wallpaper.model.WallpaperColorsViewModel import com.android.wallpaper.model.WallpaperPreviewNavigator -import com.android.wallpaper.model.WorkspaceViewModel import com.android.wallpaper.module.CurrentWallpaperInfoFactory import com.android.wallpaper.module.CustomizationSections +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.ui.viewmodel.WallpaperQuickSwitchViewModel import com.android.wallpaper.util.DisplayUtils /** Test implementation of [CustomizationSections] */ class TestCustomizationSections : CustomizationSections { - override fun getSectionControllersForScreen( + override fun getRevampedUISectionControllersForScreen( screen: CustomizationSections.Screen?, activity: FragmentActivity?, lifecycleOwner: LifecycleOwner?, wallpaperColorsViewModel: WallpaperColorsViewModel?, - workspaceViewModel: WorkspaceViewModel?, permissionRequester: PermissionRequester?, wallpaperPreviewNavigator: WallpaperPreviewNavigator?, sectionNavigationController: CustomizationSectionController.CustomizationSectionNavigationController?, savedInstanceState: Bundle?, wallpaperInfoFactory: CurrentWallpaperInfoFactory?, - displayUtils: DisplayUtils? + displayUtils: DisplayUtils?, + wallpaperQuickSwitchViewModel: WallpaperQuickSwitchViewModel, + wallpaperInteractor: WallpaperInteractor, ): MutableList<CustomizationSectionController<*>> { return arrayListOf() } @@ -35,13 +37,12 @@ class TestCustomizationSections : CustomizationSections { activity: FragmentActivity?, lifecycleOwner: LifecycleOwner?, wallpaperColorsViewModel: WallpaperColorsViewModel?, - workspaceViewModel: WorkspaceViewModel?, permissionRequester: PermissionRequester?, wallpaperPreviewNavigator: WallpaperPreviewNavigator?, sectionNavigationController: CustomizationSectionController.CustomizationSectionNavigationController?, savedInstanceState: Bundle?, - displayUtils: DisplayUtils? + displayUtils: DisplayUtils?, ): MutableList<CustomizationSectionController<*>> { return arrayListOf() } diff --git a/tests/src/com/android/wallpaper/testing/TestInjector.kt b/tests/src/com/android/wallpaper/testing/TestInjector.kt index 7c15540e..c173fa94 100644 --- a/tests/src/com/android/wallpaper/testing/TestInjector.kt +++ b/tests/src/com/android/wallpaper/testing/TestInjector.kt @@ -15,17 +15,17 @@ */ package com.android.wallpaper.testing -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import com.android.wallpaper.compat.WallpaperManagerCompat import com.android.wallpaper.config.BaseFlags import com.android.wallpaper.effects.EffectsController -import com.android.wallpaper.effects.EffectsController.EffectsServiceListener import com.android.wallpaper.model.CategoryProvider +import com.android.wallpaper.model.WallpaperColorsViewModel import com.android.wallpaper.model.WallpaperInfo import com.android.wallpaper.module.AlarmManagerWrapper import com.android.wallpaper.module.BitmapCropper @@ -51,10 +51,15 @@ import com.android.wallpaper.monitor.PerformanceMonitor import com.android.wallpaper.network.Requester import com.android.wallpaper.picker.ImagePreviewFragment import com.android.wallpaper.picker.PreviewFragment +import com.android.wallpaper.picker.customization.data.content.WallpaperClientImpl +import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor +import com.android.wallpaper.picker.customization.domain.interactor.WallpaperSnapshotRestorer import com.android.wallpaper.picker.individual.IndividualPickerFragment import com.android.wallpaper.picker.undo.data.repository.UndoRepository import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor import com.android.wallpaper.util.DisplayUtils +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope /** Test implementation of [Injector] */ @@ -79,8 +84,12 @@ open class TestInjector : Injector { private var wallpaperPreviewFragmentManager: WallpaperPreviewFragmentManager? = null private var wallpaperRefresher: WallpaperRefresher? = null private var wallpaperRotationRefresher: WallpaperRotationRefresher? = null + private var wallpaperStatusChecker: WallpaperStatusChecker? = null private var flags: BaseFlags? = null private var undoInteractor: UndoInteractor? = null + private var wallpaperInteractor: WallpaperInteractor? = null + private var wallpaperSnapshotRestorer: WallpaperSnapshotRestorer? = null + private var wallpaperColorsViewModel: WallpaperColorsViewModel? = null override fun getAlarmManagerWrapper(context: Context): AlarmManagerWrapper { return alarmManagerWrapper ?: TestAlarmManagerWrapper().also { alarmManagerWrapper = it } @@ -101,7 +110,7 @@ open class TestInjector : Injector { } } - override fun getCustomizationSections(activity: Activity): CustomizationSections { + override fun getCustomizationSections(activity: ComponentActivity): CustomizationSections { return customizationSections ?: TestCustomizationSections().also { customizationSections = it } } @@ -125,7 +134,6 @@ open class TestInjector : Injector { override fun getEffectsController( context: Context, - listener: EffectsServiceListener ): EffectsController? { return null } @@ -134,7 +142,10 @@ open class TestInjector : Injector { return exploreIntentChecker ?: TestExploreIntentChecker().also { exploreIntentChecker = it } } - override fun getIndividualPickerFragment(collectionId: String): IndividualPickerFragment { + override fun getIndividualPickerFragment( + context: Context, + collectionId: String + ): IndividualPickerFragment { return IndividualPickerFragment.newInstance(collectionId) } @@ -229,19 +240,20 @@ open class TestInjector : Injector { } override fun getWallpaperStatusChecker(): WallpaperStatusChecker { - return object : WallpaperStatusChecker { - override fun isHomeStaticWallpaperSet(context: Context): Boolean { - return true - } - - override fun isLockWallpaperSet(context: Context): Boolean { - return true - } - } + return wallpaperStatusChecker + ?: TestWallpaperStatusChecker().also { wallpaperStatusChecker = it } } override fun getFlags(): BaseFlags { - return flags ?: object : BaseFlags() {}.also { flags = it } + return flags + ?: object : BaseFlags() { + override fun isFullscreenWallpaperPreviewEnabled(context: Context): Boolean { + // This is already true by default in all environments, only keeping the + // flag for now in case we need to roll back + return true + } + } + .also { flags = it } } override fun getUndoInteractor(context: Context): UndoInteractor { @@ -252,4 +264,31 @@ open class TestInjector : Injector { HashMap() ) // Empty because we don't support undoing in WallpaperPicker2..also{} } + + override fun getWallpaperInteractor(context: Context): WallpaperInteractor { + return wallpaperInteractor + ?: WallpaperInteractor( + repository = + WallpaperRepository( + scope = GlobalScope, + client = WallpaperClientImpl(context = context), + backgroundDispatcher = Dispatchers.IO, + ), + ) + .also { wallpaperInteractor = it } + } + + override fun getWallpaperSnapshotRestorer(context: Context): WallpaperSnapshotRestorer { + return wallpaperSnapshotRestorer + ?: WallpaperSnapshotRestorer( + scope = GlobalScope, + interactor = getWallpaperInteractor(context), + ) + .also { wallpaperSnapshotRestorer = it } + } + + override fun getWallpaperColorsViewModel(): WallpaperColorsViewModel { + return wallpaperColorsViewModel + ?: WallpaperColorsViewModel().also { wallpaperColorsViewModel = it } + } } diff --git a/tests/src/com/android/wallpaper/testing/TestLiveWallpaperInfo.java b/tests/src/com/android/wallpaper/testing/TestLiveWallpaperInfo.java new file mode 100644 index 00000000..c5b54b2c --- /dev/null +++ b/tests/src/com/android/wallpaper/testing/TestLiveWallpaperInfo.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2023 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.testing; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.wallpaper.asset.Asset; +import com.android.wallpaper.model.InlinePreviewIntentFactory; +import com.android.wallpaper.model.LiveWallpaperInfo; + +import java.util.Arrays; +import java.util.List; +/** + * Test model object for a wallpaper coming from a live wallpaper component. This is essentially a + * copy of {@link TestStaticWallpaperInfo} with the minimum changes required to show a preview. + */ +public class TestLiveWallpaperInfo extends LiveWallpaperInfo { + public static final int COLOR_DEFAULT = 0xff000000; + public static final Parcelable.Creator<TestLiveWallpaperInfo> CREATOR = + new Parcelable.Creator<TestLiveWallpaperInfo>() { + @Override + public TestLiveWallpaperInfo createFromParcel(Parcel in) { + return new TestLiveWallpaperInfo(in); + } + @Override + public TestLiveWallpaperInfo[] newArray(int size) { + return new TestLiveWallpaperInfo[size]; + } + }; + private int mPixelColor; + private TestAsset mAsset; + private TestAsset mThumbAsset; + private List<String> mAttributions; + private android.app.WallpaperInfo mWallpaperComponent; + private String mActionUrl; + private String mBaseImageUrl; + private String mCollectionId; + private String mWallpaperId; + private boolean mIsAssetCorrupt; + private int mBackupPermission; + + /** Constructs a test WallpaperInfo object representing a 1x1 wallpaper of the given color. */ + public TestLiveWallpaperInfo(int pixelColor) { + this(pixelColor, null, "test-wallpaper"); + } + + /** Constructs a test WallpaperInfo object representing a 1x1 wallpaper of the given color. */ + public TestLiveWallpaperInfo(int pixelColor, android.app.WallpaperInfo info, String id) { + super(info); + mPixelColor = pixelColor; + mAttributions = Arrays.asList("Test wallpaper"); + mWallpaperComponent = null; + mIsAssetCorrupt = false; + mBackupPermission = BACKUP_ALLOWED; + mWallpaperId = id; + } + + private TestLiveWallpaperInfo(Parcel in) { + super(in); + mPixelColor = in.readInt(); + mAttributions = in.createStringArrayList(); + mActionUrl = in.readString(); + mBaseImageUrl = in.readString(); + mCollectionId = in.readString(); + mWallpaperId = in.readString(); + mIsAssetCorrupt = in.readInt() == 1; + mBackupPermission = in.readInt(); + } + + @Override + public Drawable getOverlayIcon(Context context) { + return null; + } + + @Override + public List<String> getAttributions(Context context) { + return mAttributions; + } + + /** + * Override default "Test wallpaper" attributions for testing. + */ + public void setAttributions(List<String> attributions) { + mAttributions = attributions; + } + + @Override + public CharSequence getActionDescription(Context context) { + return null; + } + + @Override + public String getActionUrl(Context unused) { + return mActionUrl; + } + + /** Sets the action URL for this wallpaper. */ + public void setActionUrl(String actionUrl) { + mActionUrl = actionUrl; + } + + @Override + public String getBaseImageUrl() { + return mBaseImageUrl; + } + + /** Sets the base image URL for this wallpaper. */ + public void setBaseImageUrl(String baseImageUrl) { + mBaseImageUrl = baseImageUrl; + } + + @Override + public String getCollectionId(Context unused) { + return mCollectionId; + } + + /** Sets the collection ID for this wallpaper. */ + public void setCollectionId(String collectionId) { + mCollectionId = collectionId; + } + + @Override + public String getWallpaperId() { + return mWallpaperId; + + } + /** Sets the ID for this wallpaper. */ + public void setWallpaperId(String wallpaperId) { + mWallpaperId = wallpaperId; + } + + @Override + public Asset getAsset(Context context) { + if (mAsset == null) { + mAsset = new TestAsset(mPixelColor, mIsAssetCorrupt); + } + return mAsset; + } + + @Override + public Asset getThumbAsset(Context context) { + if (mThumbAsset == null) { + mThumbAsset = new TestAsset(mPixelColor, mIsAssetCorrupt); + } + return mThumbAsset; + } + + @Override + public void showPreview(Activity srcActivity, + InlinePreviewIntentFactory inlinePreviewIntentFactory, int requestCode) { + srcActivity.startActivityForResult( + inlinePreviewIntentFactory.newIntent(srcActivity, this), requestCode); + } + + @Override + @BackupPermission + public int getBackupPermission() { + return mBackupPermission; + } + + public void setBackupPermission(@BackupPermission int backupPermission) { + mBackupPermission = backupPermission; + } + + @Override + public android.app.WallpaperInfo getWallpaperComponent() { + return mWallpaperComponent; + } + + public void setWallpaperComponent(android.app.WallpaperInfo wallpaperComponent) { + mWallpaperComponent = wallpaperComponent; + } + + /** + * Simulates that the {@link Asset} instances returned by calls to #getAsset and #getThumbAsset + * on this object are "corrupt" and will fail to perform decode operations such as + * #decodeBitmap, #decodeBitmapRegion, #decodeRawDimensions, etc (these methods will call their + * callbacks with null instead of meaningful objects). + */ + public void corruptAssets() { + mIsAssetCorrupt = true; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + super.writeToParcel(parcel, i); + parcel.writeInt(mPixelColor); + parcel.writeStringList(mAttributions); + parcel.writeString(mActionUrl); + parcel.writeString(mBaseImageUrl); + parcel.writeString(mCollectionId); + parcel.writeString(mWallpaperId); + parcel.writeInt(mIsAssetCorrupt ? 1 : 0); + parcel.writeInt(mBackupPermission); + } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof TestLiveWallpaperInfo) { + return mPixelColor == ((TestLiveWallpaperInfo) object).mPixelColor; + } + return false; + } + + @Override + public int hashCode() { + return mPixelColor; + } +} diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java b/tests/src/com/android/wallpaper/testing/TestStaticWallpaperInfo.java index 0c20456a..9576766b 100644 --- a/tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java +++ b/tests/src/com/android/wallpaper/testing/TestStaticWallpaperInfo.java @@ -31,18 +31,18 @@ import java.util.List; /** * Test model object for a wallpaper coming from local drawable resources. */ -public class TestWallpaperInfo extends WallpaperInfo { +public class TestStaticWallpaperInfo extends WallpaperInfo { public static final int COLOR_DEFAULT = 0xff000000; - public static final Parcelable.Creator<TestWallpaperInfo> CREATOR = - new Parcelable.Creator<TestWallpaperInfo>() { + public static final Parcelable.Creator<TestStaticWallpaperInfo> CREATOR = + new Parcelable.Creator<TestStaticWallpaperInfo>() { @Override - public TestWallpaperInfo createFromParcel(Parcel in) { - return new TestWallpaperInfo(in); + public TestStaticWallpaperInfo createFromParcel(Parcel in) { + return new TestStaticWallpaperInfo(in); } @Override - public TestWallpaperInfo[] newArray(int size) { - return new TestWallpaperInfo[size]; + public TestStaticWallpaperInfo[] newArray(int size) { + return new TestStaticWallpaperInfo[size]; } }; private int mPixelColor; @@ -58,12 +58,12 @@ public class TestWallpaperInfo extends WallpaperInfo { private int mBackupPermission; /** Constructs a test WallpaperInfo object representing a 1x1 wallpaper of the given color. */ - public TestWallpaperInfo(int pixelColor) { + public TestStaticWallpaperInfo(int pixelColor) { this(pixelColor, "test-wallpaper"); } /** Constructs a test WallpaperInfo object representing a 1x1 wallpaper of the given color. */ - public TestWallpaperInfo(int pixelColor, String id) { + public TestStaticWallpaperInfo(int pixelColor, String id) { mPixelColor = pixelColor; mAttributions = Arrays.asList("Test wallpaper"); mWallpaperComponent = null; @@ -72,7 +72,7 @@ public class TestWallpaperInfo extends WallpaperInfo { mWallpaperId = id; } - private TestWallpaperInfo(Parcel in) { + private TestStaticWallpaperInfo(Parcel in) { super(in); mPixelColor = in.readInt(); mAttributions = in.createStringArrayList(); @@ -185,10 +185,9 @@ public class TestWallpaperInfo extends WallpaperInfo { /** * Simulates that the {@link Asset} instances returned by calls to #getAsset and #getThumbAsset - * on - * this object are "corrupt" and will fail to perform decode operations such as #decodeBitmap, - * #decodeBitmapRegion, #decodeRawDimensions, etc (these methods will call their callbacks with - * null instead of meaningful objects). + * on this object are "corrupt" and will fail to perform decode operations such as + * #decodeBitmap, #decodeBitmapRegion, #decodeRawDimensions, etc (these methods will call their + * callbacks with null instead of meaningful objects). */ public void corruptAssets() { mIsAssetCorrupt = true; @@ -217,8 +216,8 @@ public class TestWallpaperInfo extends WallpaperInfo { if (object == this) { return true; } - if (object instanceof TestWallpaperInfo) { - return mPixelColor == ((TestWallpaperInfo) object).mPixelColor; + if (object instanceof TestStaticWallpaperInfo) { + return mPixelColor == ((TestStaticWallpaperInfo) object).mPixelColor; } return false; } diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java b/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java index e5ea0be1..1ead2601 100644 --- a/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java +++ b/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java @@ -201,7 +201,7 @@ public class TestWallpaperPersister implements WallpaperPersister { mCurrentLockWallpaper = mPendingLockWallpaper; mPendingLockWallpaper = null; } - mCallback.onSuccess(mWallpaperInfo); + mCallback.onSuccess(mWallpaperInfo, mDestination); mWallpaperChangedNotifier.notifyWallpaperChanged(); } } @@ -211,7 +211,12 @@ public class TestWallpaperPersister implements WallpaperPersister { } @Override - public void onLiveWallpaperSet() { + public void onLiveWallpaperSet(@Destination int destination) { + } + + @Override + public void setLiveWallpaperMetadata(WallpaperInfo wallpaperInfo, String effects, + @Destination int destination) { } /** Returns the last requested wallpaper bitmap scale. */ @@ -230,15 +235,18 @@ public class TestWallpaperPersister implements WallpaperPersister { return mWallpaperPosition; } + @Override public boolean saveStaticWallpaperMetadata(List<String> attributions, String actionUrl, int actionLabelRes, int actionIconRes, String collectionId, int wallpaperId) { return false; } + @Override public int getDefaultWhichWallpaper() { return 0; } + @Override public int setBitmapToWallpaperManagerCompat(Bitmap wallpaperBitmap, boolean allowBackup, int whichWallpaper) { return 0; diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java b/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java index 5faede46..54bca11c 100644 --- a/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java +++ b/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java @@ -50,8 +50,8 @@ public class TestWallpaperPreferences implements WallpaperPreferences { private List<String> mHomeScreenAttributions; private long mHomeScreenBitmapHashCode; private int mHomeWallpaperManagerId; - private String mHomeScreenPackageName; private String mHomeScreenServiceName; + private String mLockScreenServiceName; private String mHomeActionUrl; private String mHomeBaseImageUrl; private String mHomeCollectionId; @@ -81,8 +81,9 @@ public class TestWallpaperPreferences implements WallpaperPreferences { private int mHomeWallpaperActionIconRes; private int mLockWallpaperActionLabelRes; private int mLockWallpaperActionIconRes; + private String mHomeWallpaperEffects; + private String mLockWallpaperEffects; private HashMap<String, String> mWallStoredColor; - private String mWallpaperEffects; public TestWallpaperPreferences() { mWallpaperPresentationMode = WallpaperPreferences.PRESENTATION_MODE_STATIC; @@ -189,7 +190,7 @@ public class TestWallpaperPreferences implements WallpaperPreferences { mHomeScreenAttributions = null; mWallpaperPresentationMode = WallpaperPreferences.PRESENTATION_MODE_STATIC; mHomeScreenBitmapHashCode = 0; - mHomeScreenPackageName = null; + mHomeScreenServiceName = null; mHomeWallpaperManagerId = 0; } @@ -204,16 +205,6 @@ public class TestWallpaperPreferences implements WallpaperPreferences { } @Override - public String getHomeWallpaperPackageName() { - return mHomeScreenPackageName; - } - - @Override - public void setHomeWallpaperPackageName(String packageName) { - mHomeScreenPackageName = packageName; - } - - @Override public String getHomeWallpaperServiceName() { return mHomeScreenServiceName; } @@ -246,6 +237,16 @@ public class TestWallpaperPreferences implements WallpaperPreferences { } @Override + public String getHomeWallpaperEffects() { + return mHomeWallpaperEffects; + } + + @Override + public void setHomeWallpaperEffects(String effects) { + mHomeWallpaperEffects = effects; + } + + @Override public List<String> getLockWallpaperAttributions() { return mLockScreenAttributions; } @@ -344,6 +345,26 @@ public class TestWallpaperPreferences implements WallpaperPreferences { } @Override + public String getLockWallpaperServiceName() { + return mLockScreenServiceName; + } + + @Override + public void setLockWallpaperServiceName(String serviceName) { + mLockScreenServiceName = serviceName; + } + + @Override + public String getLockWallpaperEffects() { + return mLockWallpaperEffects; + } + + @Override + public void setLockWallpaperEffects(String wallpaperEffects) { + mLockWallpaperEffects = wallpaperEffects; + } + + @Override public void addDailyRotation(long timestamp) { mDailyRotations.add(timestamp); } @@ -601,16 +622,6 @@ public class TestWallpaperPreferences implements WallpaperPreferences { } } - @Override - public String getWallpaperEffects() { - return mWallpaperEffects; - } - - @Override - public void setWallpaperEffects(String effects) { - mWallpaperEffects = effects; - } - private int getCurrentDate() { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.US); diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperStatusChecker.kt b/tests/src/com/android/wallpaper/testing/TestWallpaperStatusChecker.kt new file mode 100644 index 00000000..4d386ab2 --- /dev/null +++ b/tests/src/com/android/wallpaper/testing/TestWallpaperStatusChecker.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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.testing + +import android.content.Context +import com.android.wallpaper.module.WallpaperStatusChecker + +class TestWallpaperStatusChecker : WallpaperStatusChecker { + private var isHomeStaticWallpaperSet = true + private var isLockWallpaperSet = true + + fun setHomeStaticWallpaperSet(isSet: Boolean) { + isHomeStaticWallpaperSet = isSet + } + + override fun isHomeStaticWallpaperSet(context: Context): Boolean { + return isHomeStaticWallpaperSet + } + + fun setLockWallpaperSet(isSet: Boolean) { + isLockWallpaperSet = isSet + } + + override fun isLockWallpaperSet(context: Context): Boolean { + return isLockWallpaperSet + } +} diff --git a/tests/src/com/android/wallpaper/testing/UndoTestUtil.kt b/tests/src/com/android/wallpaper/testing/UndoTestUtil.kt index 0f30db2a..04cd7565 100644 --- a/tests/src/com/android/wallpaper/testing/UndoTestUtil.kt +++ b/tests/src/com/android/wallpaper/testing/UndoTestUtil.kt @@ -18,6 +18,7 @@ package com.android.wallpaper.testing import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer +import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot val FAKE_RESTORERS = @@ -39,18 +40,18 @@ fun snapshot(ownerId: Int, version: Int): RestorableSnapshot { class FakeSnapshotRestorer( private val ownerId: Int, ) : SnapshotRestorer { - private lateinit var updater: (RestorableSnapshot) -> Unit + private lateinit var store: SnapshotStore var restored: RestorableSnapshot? = null private set fun update(version: Int) { - updater(snapshot(ownerId, version)) + store.store(snapshot(ownerId, version)) } override suspend fun setUpSnapshotRestorer( - updater: (RestorableSnapshot) -> Unit, + store: SnapshotStore, ): RestorableSnapshot { - this.updater = updater + this.store = store return snapshot( ownerId = ownerId, version = 0, |