summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHyunyoung Song <hyunyoungs@google.com>2019-11-20 00:22:33 -0800
committerHyunyoung Song <hyunyoungs@google.com>2019-11-20 08:43:12 +0000
commit9734f7414149c6fc9f0a704576ad17e4c09ec2d8 (patch)
treef1225c36792ebf211f4f90937fa4092dfd0fd3db
parentd6b718de5f6bd24410087482a7687bb1fd09536b (diff)
parent6fc434eb5a3a3f2de222dd155b584adf0611353e (diff)
downloadandroid_packages_apps_WallpaperPicker2-9734f7414149c6fc9f0a704576ad17e4c09ec2d8.tar.gz
android_packages_apps_WallpaperPicker2-9734f7414149c6fc9f0a704576ad17e4c09ec2d8.tar.bz2
android_packages_apps_WallpaperPicker2-9734f7414149c6fc9f0a704576ad17e4c09ec2d8.zip
Merging from ub-launcher3-qt-future-dev @ build 6018744
Test: manual, presubmit on the source branch http://x20/teams/android-launcher/merge/ub-launcher3-qt-future-dev_6018744.html Change-Id: I619b51952d3d8577b9929d81ca3ce2ca8cc2fac9 Merged-In: Ied2409b3978f5f0429bd05a9f2c855f46a5f0bfc
-rwxr-xr-xAndroid.mk31
-rwxr-xr-xAndroidManifest.xml7
-rw-r--r--PREUPLOAD.cfg2
-rw-r--r--libs/style_protos.jarbin53134 -> 0 bytes
-rw-r--r--res/drawable/gradient_background.xml24
-rw-r--r--res/drawable/ic_delete_24px.xml30
-rw-r--r--res/drawable/ic_settings.xml27
-rwxr-xr-xres/layout/fragment_image_preview.xml (renamed from res/layout/fragment_preview.xml)27
-rwxr-xr-xres/layout/fragment_live_preview.xml93
-rw-r--r--res/layout/preview_page_info.xml3
-rw-r--r--res/layout/preview_page_settings.xml45
-rwxr-xr-xres/menu/preview_menu.xml14
-rw-r--r--res/values-ar/strings.xml4
-rw-r--r--res/values-en-rCA/strings.xml83
-rw-r--r--res/values-en-rXC/strings.xml83
-rwxr-xr-xres/values/dimens.xml1
-rwxr-xr-xres/values/strings.xml15
-rwxr-xr-xres/values/styles.xml14
-rwxr-xr-xsrc/com/android/wallpaper/model/CurrentWallpaperInfoV16.java139
-rwxr-xr-xsrc/com/android/wallpaper/model/CurrentWallpaperInfoVN.java14
-rwxr-xr-xsrc/com/android/wallpaper/model/InlinePreviewIntentFactory.java12
-rwxr-xr-xsrc/com/android/wallpaper/model/LiveWallpaperInfo.java40
-rwxr-xr-xsrc/com/android/wallpaper/model/WallpaperRotationInitializer.java7
-rwxr-xr-xsrc/com/android/wallpaper/module/BaseWallpaperInjector.java19
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java41
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultLiveWallpaperStatusChecker.java42
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultRotatingWallpaperComponentChecker.java77
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultWallpaperPersister.java449
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultWallpaperPreferences.java340
-rwxr-xr-xsrc/com/android/wallpaper/module/DefaultWallpaperRefresher.java41
-rwxr-xr-xsrc/com/android/wallpaper/module/Injector.java4
-rwxr-xr-xsrc/com/android/wallpaper/module/NoBackupImageWallpaper.java1018
-rwxr-xr-xsrc/com/android/wallpaper/module/RotatingWallpaperComponentChecker.java69
-rw-r--r--src/com/android/wallpaper/module/RotationWallpaperMoveReceiver.java77
-rw-r--r--src/com/android/wallpaper/module/RotationWallpaperUpdateReceiver.java111
-rwxr-xr-xsrc/com/android/wallpaper/module/WallpaperPreferenceKeys.java54
-rw-r--r--src/com/android/wallpaper/module/WallpaperSetter.java5
-rwxr-xr-xsrc/com/android/wallpaper/picker/ImagePreviewFragment.java464
-rw-r--r--src/com/android/wallpaper/picker/LivePreviewFragment.java655
-rwxr-xr-xsrc/com/android/wallpaper/picker/PreviewFragment.java689
-rwxr-xr-xsrc/com/android/wallpaper/picker/StartRotationDialogFragment.java25
-rwxr-xr-xsrc/com/android/wallpaper/picker/individual/IndividualPickerActivity.java36
-rwxr-xr-xsrc/com/android/wallpaper/picker/individual/IndividualPickerFragment.java119
-rw-r--r--src/com/android/wallpaper/widget/ConstraintViewPager.java62
-rwxr-xr-xsrc_override/com/android/wallpaper/module/WallpapersInjector.java8
-rw-r--r--tests/Android.mk59
-rw-r--r--tests/AndroidManifest.xml33
-rw-r--r--tests/src/com/android/wallpaper/picker/PreviewActivityTest.java510
-rw-r--r--tests/src/com/android/wallpaper/picker/individual/IndividualPickerActivityTest.java496
-rw-r--r--tests/src/com/android/wallpaper/testing/TestAlarmManagerWrapper.java71
-rw-r--r--tests/src/com/android/wallpaper/testing/TestAsset.java99
-rw-r--r--tests/src/com/android/wallpaper/testing/TestBitmapCropper.java58
-rw-r--r--tests/src/com/android/wallpaper/testing/TestCategoryProvider.java94
-rw-r--r--tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java70
-rw-r--r--tests/src/com/android/wallpaper/testing/TestExploreIntentChecker.java44
-rw-r--r--tests/src/com/android/wallpaper/testing/TestFormFactorChecker.java41
-rw-r--r--tests/src/com/android/wallpaper/testing/TestInjector.java244
-rw-r--r--tests/src/com/android/wallpaper/testing/TestLoggingOptInStatusProvider.java27
-rw-r--r--tests/src/com/android/wallpaper/testing/TestNetworkStatusNotifier.java61
-rw-r--r--tests/src/com/android/wallpaper/testing/TestPartnerProvider.java58
-rw-r--r--[-rwxr-xr-x]tests/src/com/android/wallpaper/testing/TestPerformanceMonitor.java (renamed from src/com/android/wallpaper/module/LiveWallpaperStatusChecker.java)17
-rw-r--r--tests/src/com/android/wallpaper/testing/TestSystemFeatureChecker.java41
-rw-r--r--tests/src/com/android/wallpaper/testing/TestUserEventLogger.java289
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperCategory.java59
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java228
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperManagerCompat.java135
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java223
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java457
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperRefresher.java81
-rw-r--r--tests/src/com/android/wallpaper/testing/TestWallpaperRotationInitializer.java133
70 files changed, 6012 insertions, 2736 deletions
diff --git a/Android.mk b/Android.mk
index e7e051e..39eeeb6 100755
--- a/Android.mk
+++ b/Android.mk
@@ -16,24 +16,13 @@
LOCAL_PATH := $(call my-dir)
-#
-# Prebuilt Java Libraries
-#
-include $(CLEAR_VARS)
-LOCAL_MODULE := libStyleProtos
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_SRC_FILES := libs/style_protos.jar
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_SDK_VERSION := current
-include $(BUILD_PREBUILT)
-
include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := wallpaper2-glide-target
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../prebuilts/maven_repo/bumptech/com/github/bumptech/glide/glide/SNAPSHOT/glide-SNAPSHOT$(COMMON_JAVA_PACKAGE_SUFFIX)
LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_JETIFIER_ENABLED := true
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -64,7 +53,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/../../../external/subsampling-scale-image-vi
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 21
+LOCAL_MIN_SDK_VERSION := 26
LOCAL_MODULE := wallpaper-subsampling-scale-image-view
LOCAL_MANIFEST_FILE := ../../../external/subsampling-scale-image-view/library/src/main/AndroidManifest.xml
@@ -82,6 +71,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.appcompat_appcompat \
androidx.cardview_cardview \
androidx.recyclerview_recyclerview \
+ androidx.slice_slice-view \
androidx-constraintlayout_constraintlayout \
com.google.android.material_material \
androidx.exifinterface_exifinterface \
@@ -99,14 +89,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_MANIFEST_FILE := AndroidManifest.xml
-ifneq (,$(wildcard frameworks/base))
- LOCAL_STATIC_JAVA_LIBRARIES += SystemUISharedLib styleprotosnano
- LOCAL_PRIVATE_PLATFORM_APIS := true
-else
- LOCAL_STATIC_JAVA_LIBRARIES += libSharedSystemUI libStyleProtos
- LOCAL_SDK_VERSION := current
-endif
-
+LOCAL_SDK_VERSION := current
LOCAL_MODULE := WallpaperPicker2CommonDepsLib
LOCAL_PRIVILEGED_MODULE := true
@@ -131,12 +114,18 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PRIVILEGED_MODULE := true
+
ifneq (,$(wildcard frameworks/base))
LOCAL_PRIVATE_PLATFORM_APIS := true
else
LOCAL_SDK_VERSION := system_current
+ LOCAL_STATIC_JAVA_LIBRARIES += libSharedWallpaper
endif
+
LOCAL_PACKAGE_NAME := WallpaperPicker2
LOCAL_JETIFIER_ENABLED := true
include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0192398..6096d10 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:name="com.android.wallpaper.NOTIFY_ROTATING_WALLPAPER_CHANGED" />
<application
- tools:replace="android:name"
+ tools:replace="android:icon,android:name"
android:allowBackup="true"
android:icon="@mipmap/product_logo_wallpapers_launcher_color_48"
android:label="@string/app_name"
@@ -37,7 +37,7 @@
<activity android:name="com.android.wallpaper.picker.TopLevelPickerActivity"
android:label="@string/app_name"
android:theme="@style/WallpaperTheme"
- android:resizeableActivity="true">
+ android:resizeableActivity="false">
<intent-filter>
<action android:name="android.intent.action.SET_WALLPAPER"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -50,14 +50,13 @@
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<activity android:name="com.android.wallpaper.picker.individual.IndividualPickerActivity"
android:label="@string/app_name"
android:theme="@style/WallpaperTheme"
- android:resizeableActivity="true"
+ android:resizeableActivity="false"
android:parentActivityName="com.android.wallpaper.picker.TopLevelPickerActivity">
</activity>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..f3db20e
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/libs/style_protos.jar b/libs/style_protos.jar
deleted file mode 100644
index 8708555..0000000
--- a/libs/style_protos.jar
+++ /dev/null
Binary files differ
diff --git a/res/drawable/gradient_background.xml b/res/drawable/gradient_background.xml
new file mode 100644
index 0000000..47d864a
--- /dev/null
+++ b/res/drawable/gradient_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+
+ Copyright (C) 2019 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">
+ <gradient android:angle="270"
+ android:centerY=".1"
+ android:startColor="@color/translucent_black"
+ android:centerColor="@android:color/transparent"
+ android:endColor="@android:color/transparent"
+ />
+</shape> \ No newline at end of file
diff --git a/res/drawable/ic_delete_24px.xml b/res/drawable/ic_delete_24px.xml
new file mode 100644
index 0000000..bc83f36
--- /dev/null
+++ b/res/drawable/ic_delete_24px.xml
@@ -0,0 +1,30 @@
+<!--
+ Copyright (C) 2019 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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V6h1V4H15zM17,19H7V6h10V19z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9,8h2v9h-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M13,8h2v9h-2z"/>
+</vector>
diff --git a/res/drawable/ic_settings.xml b/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..f24a0a8
--- /dev/null
+++ b/res/drawable/ic_settings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+
+ Copyright (C) 2019 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:height="24.0dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:width="24.0dp" >
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z" />
+
+</vector> \ No newline at end of file
diff --git a/res/layout/fragment_preview.xml b/res/layout/fragment_image_preview.xml
index 82c481f..6c3e324 100755
--- a/res/layout/fragment_preview.xml
+++ b/res/layout/fragment_image_preview.xml
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -37,13 +52,19 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom">
- <include
- layout="@layout/preview_page_info"
+ <FrameLayout
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@drawable/preview_bottom_sheet_background"
+ android:theme="@style/WallpaperPicker.BottomPaneStyle"
app:behavior_peekHeight="@dimen/preview_attribution_pane_collapsed_height"
- app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"/>
+ app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
+ <include
+ layout="@layout/preview_page_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/res/layout/fragment_live_preview.xml b/res/layout/fragment_live_preview.xml
new file mode 100755
index 0000000..418a289
--- /dev/null
+++ b/res/layout/fragment_live_preview.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="false">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/preview_gradient_background_height"
+ android:layout_gravity="top"
+ android:background="@drawable/gradient_background"/>
+
+ <FrameLayout
+ android:id="@+id/loading"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:forceHasOverlappingRendering="false">
+
+ <ImageView
+ android:id="@+id/loading_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="visible"
+ android:fitsSystemWindows="false"/>
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+
+ <androidx.coordinatorlayout.widget.CoordinatorLayout
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom">
+
+ <LinearLayout
+ android:id="@+id/bottom_sheet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@drawable/preview_bottom_sheet_background"
+ android:theme="@style/WallpaperPicker.BottomPaneStyle"
+ app:behavior_peekHeight="@dimen/preview_attribution_pane_collapsed_height"
+ app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tablayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:tabTextAppearance="@style/WallpaperPicker.Preview.TextAppearance.NoAllCaps"
+ app:tabIndicatorColor="?android:attr/textColorPrimary"
+ android:visibility="gone"/>
+
+ <com.android.wallpaper.widget.ConstraintViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ </androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ style="@style/TranslucentToolbarStyle"/>
+
+ </FrameLayout>
+
+</FrameLayout>
diff --git a/res/layout/preview_page_info.xml b/res/layout/preview_page_info.xml
index 9299426..2489561 100644
--- a/res/layout/preview_page_info.xml
+++ b/res/layout/preview_page_info.xml
@@ -21,8 +21,7 @@
android:layout_width="match_parent"
android:orientation="vertical"
android:paddingHorizontal="@dimen/preview_attribution_pane_horizontal_padding"
- android:background="@drawable/preview_bottom_sheet_background"
- android:theme="@android:style/Theme.DeviceDefault.Settings">
+ android:theme="@style/WallpaperPicker.BottomPaneStyle">
<Space
android:id="@+id/preview_attribution_pane_title_spacer"
diff --git a/res/layout/preview_page_settings.xml b/res/layout/preview_page_settings.xml
new file mode 100644
index 0000000..72e83a5
--- /dev/null
+++ b/res/layout/preview_page_settings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2019 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:gravity="center_horizontal"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:paddingHorizontal="@dimen/preview_attribution_pane_horizontal_padding"
+ android:theme="@style/WallpaperPicker.BottomPaneStyle">
+
+ <androidx.slice.widget.SliceView
+ android:id="@+id/settings_slice"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <Space
+ android:id="@+id/preview_attribution_pane_spacer"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <Button
+ style="@style/ButtonStyle"
+ android:id="@+id/preview_attribution_pane_set_wallpaper_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_wallpaper_button_text"/>
+
+</LinearLayout>
diff --git a/res/menu/preview_menu.xml b/res/menu/preview_menu.xml
index 7c9d610..f83560e 100755
--- a/res/menu/preview_menu.xml
+++ b/res/menu/preview_menu.xml
@@ -20,4 +20,18 @@
app:actionLayout="@layout/preview_action"
app:showAsAction="always|withText"
android:title="@string/preview"/>
+
+ <item
+ android:id="@+id/configure"
+ android:icon="@drawable/ic_settings"
+ app:showAsAction="ifRoom"
+ android:title="@string/configure_wallpaper"
+ android:visible="false"/>
+
+ <item
+ android:id="@+id/delete_wallpaper"
+ android:icon="@drawable/ic_delete_24px"
+ app:showAsAction="ifRoom"
+ android:title="@string/delete_live_wallpaper"
+ android:visible="false"/>
</menu>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 2a6c183..b35d76f 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -30,11 +30,11 @@
<string name="rotating_wallpaper_presentation_mode_message" msgid="3361676041605733288">"خلفية يومية"</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="lock_screen_message" msgid="1534506081955058013">"شاشة القفل"</string>
<string name="home_and_lock_short_label" msgid="2937922943541927983">"الشاشة الرئيسية وشاشة التأمين"</string>
<string name="set_wallpaper_dialog_message" msgid="6114951028768599417">"تعيين كخلفية"</string>
<string name="set_wallpaper_home_screen_destination" msgid="7315594722013109354">"الشاشة الرئيسية"</string>
- <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"شاشة التأمين"</string>
+ <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"شاشة القفل"</string>
<string name="set_wallpaper_both_destination" msgid="6967226064958263939">"الشاشة الرئيسية وشاشة التأمين"</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>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..158ce10
--- /dev/null
+++ b/res/values-en-rCA/strings.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_app_name" msgid="1719889291772891695">"Wallpapers"</string>
+ <!-- no translation found for app_name (8773648973927541493) -->
+ <skip />
+ <string name="select_wallpaper_label" msgid="6989581259339646085">"Wallpaper categories"</string>
+ <string name="set_wallpaper_button_text" msgid="4426286890442731310">"Set Wallpaper"</string>
+ <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"Setting wallpaper…"</string>
+ <string name="try_again" msgid="8278874823700921234">"Try again"</string>
+ <string name="set_wallpaper_error_message" msgid="6819986999041085130">"Unable to set wallpaper."</string>
+ <string name="load_wallpaper_error_message" msgid="7913278480467707374">"Unable to load wallpaper. The image is either corrupted or unavailable."</string>
+ <string name="static_wallpaper_presentation_mode_message" msgid="417940227049360906">"Currently set"</string>
+ <string name="rotating_wallpaper_presentation_mode_message" msgid="3361676041605733288">"Daily wallpaper"</string>
+ <string name="wallpaper_destination_both" msgid="1124197176741944063">"Home &amp; Lock screen"</string>
+ <string name="home_screen_message" msgid="106444102822522813">"Home screen"</string>
+ <string name="lock_screen_message" msgid="1534506081955058013">"Lock screen"</string>
+ <string name="home_and_lock_short_label" msgid="2937922943541927983">"Home &amp; Lock"</string>
+ <string name="set_wallpaper_dialog_message" msgid="6114951028768599417">"Set wallpaper"</string>
+ <string name="set_wallpaper_home_screen_destination" msgid="7315594722013109354">"Home screen"</string>
+ <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"Lock screen"</string>
+ <string name="set_wallpaper_both_destination" msgid="6967226064958263939">"Home screen and lock screen"</string>
+ <string name="no_backup_image_wallpaper_label" msgid="6316627676107284851">"Rotating Image Wallpaper"</string>
+ <string name="permission_needed_explanation" msgid="139166837541426823">"To display the current wallpaper here, <xliff:g id="APP_NAME">%1$s</xliff:g> needs access to your device\'s storage."</string>
+ <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"To display the current wallpaper here, Wallpapers needs access to your device’s storage.\n\nTo change this setting, go to the Permissions area of the Wallpapers’ app info."</string>
+ <string name="permission_needed_allow_access_button_label" msgid="1943133660612924306">"Allow access"</string>
+ <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"Live wallpaper service for rotating wallpapers"</string>
+ <string name="daily_refresh_tile_title" msgid="3270456074558525091">"Daily wallpaper"</string>
+ <string name="daily_refresh_tile_subtitle" msgid="3976682014885446443">"Tap to turn on"</string>
+ <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"Wallpaper will change automatically every day. To finish setup, tap &lt;strong&gt;Set wallpaper&lt;/strong&gt; on the next screen."</string>
+ <string name="start_rotation_dialog_wifi_only_option_message" msgid="3126269859713666225">"Download future wallpapers on Wi-Fi only"</string>
+ <string name="start_rotation_dialog_continue" msgid="276678987852274872">"Continue"</string>
+ <string name="start_rotation_progress_message" msgid="7872623873682262083">"Downloading first wallpaper…"</string>
+ <string name="start_rotation_error_message" msgid="3053799836719618972">"Unable to download first wallpaper. Please check your network settings and try again."</string>
+ <string name="start_rotation_dialog_body" msgid="7903554799046364916">"Wallpaper will change automatically every day"</string>
+ <string name="settings_button_label" msgid="8724734130079207955">"Settings"</string>
+ <string name="explore" msgid="7468719504199497281">"Explore"</string>
+ <string name="next_wallpaper" msgid="3911873152952596232">"Next wallpaper"</string>
+ <string name="wallpaper_disabled_message" msgid="7309484130562148185">"Setting a wallpaper is disabled on this device"</string>
+ <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"Setting a wallpaper is disabled by your device administrator"</string>
+ <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"Wallpaper set successfully"</string>
+ <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"You need an Internet connection to view wallpapers. Please connect and try again."</string>
+ <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"Currently set home screen wallpaper thumbnail"</string>
+ <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"Currently set lock screen wallpaper thumbnail"</string>
+ <string name="currently_set_wallpaper_thumbnail" msgid="8651887838745545107">"Currently set wallpaper thumbnail"</string>
+ <string name="wallpaper_thumbnail" msgid="569931475923605974">"Wallpaper thumbnail"</string>
+ <string name="explore_home_screen" msgid="8756346794535765482">"Explore home screen wallpaper"</string>
+ <string name="explore_lock_screen" msgid="268938342103703665">"Explore lock screen wallpaper"</string>
+ <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"Refresh daily home screen wallpaper"</string>
+ <string name="refresh_daily_wallpaper_content_description" msgid="4362142658237147583">"Refresh daily wallpaper"</string>
+ <string name="refreshing_daily_wallpaper_dialog_message" msgid="1975910873362855761">"Refreshing daily wallpaper…"</string>
+ <string name="refresh_daily_wallpaper_failed_message" msgid="4749879993812557166">"Failed to refresh daily wallpaper. Please check your network connection and try again."</string>
+ <string name="collapse_attribution_panel" msgid="4367971404848122275">"Collapse wallpaper info panel"</string>
+ <string name="expand_attribution_panel" msgid="6975094181456095915">"Expand wallpaper info panel"</string>
+ <string name="on_device_wallpapers_category_title" msgid="805819102071369004">"On-device wallpapers"</string>
+ <string name="on_device_wallpapers_category_title_desktop" msgid="316919420410065369">"On device"</string>
+ <string name="on_device_wallpaper_title" msgid="5262564748034629524">"Android wallpaper"</string>
+ <string name="live_wallpapers_category_title" msgid="1814374812192366349">"Live wallpapers"</string>
+ <string name="my_photos_category_title" msgid="4294567122144565273">"My photos"</string>
+ <string name="my_photos_generic_wallpaper_title" msgid="7002867526154631172">"My photo"</string>
+ <string name="fallback_wallpaper_title" msgid="6154655421012506001">"Wallpaper"</string>
+ <string name="app_not_found" msgid="4431461707854088231">"App isn\'t installed."</string>
+ <string name="center_wallpaper_position" msgid="4166894762352288883">"Centre"</string>
+ <string name="center_crop_wallpaper_position" msgid="1681980019815343348">"Centre crop"</string>
+ <string name="stretch_wallpaper_position" msgid="5002680983147456935">"Stretch"</string>
+ <string name="preview" msgid="1774602101743861071">"Preview"</string>
+</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..b06a217
--- /dev/null
+++ b/res/values-en-rXC/strings.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2017 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_app_name" msgid="1719889291772891695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎Wallpapers‎‏‎‎‏‎"</string>
+ <!-- no translation found for app_name (8773648973927541493) -->
+ <skip />
+ <string name="select_wallpaper_label" msgid="6989581259339646085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎Wallpaper categories‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_button_text" msgid="4426286890442731310">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎Set Wallpaper‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_progress_message" msgid="7986528287618716715">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎Setting wallpaper…‎‏‎‎‏‎"</string>
+ <string name="try_again" msgid="8278874823700921234">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎Try again‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_error_message" msgid="6819986999041085130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎Unable to set wallpaper.‎‏‎‎‏‎"</string>
+ <string name="load_wallpaper_error_message" msgid="7913278480467707374">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎Unable to load wallpaper. The image is either corrupted or unavailable.‎‏‎‎‏‎"</string>
+ <string name="static_wallpaper_presentation_mode_message" msgid="417940227049360906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎Currently set‎‏‎‎‏‎"</string>
+ <string name="rotating_wallpaper_presentation_mode_message" msgid="3361676041605733288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎Daily wallpaper‎‏‎‎‏‎"</string>
+ <string name="wallpaper_destination_both" msgid="1124197176741944063">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎Home &amp; Lock screen‎‏‎‎‏‎"</string>
+ <string name="home_screen_message" msgid="106444102822522813">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎Home screen‎‏‎‎‏‎"</string>
+ <string name="lock_screen_message" msgid="1534506081955058013">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎Lock screen‎‏‎‎‏‎"</string>
+ <string name="home_and_lock_short_label" msgid="2937922943541927983">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‎Home &amp; Lock‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_dialog_message" msgid="6114951028768599417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎Set wallpaper‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_home_screen_destination" msgid="7315594722013109354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎Home screen‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_lock_screen_destination" msgid="6224685559375417945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‎Lock screen‎‏‎‎‏‎"</string>
+ <string name="set_wallpaper_both_destination" msgid="6967226064958263939">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎Home screen and lock screen‎‏‎‎‏‎"</string>
+ <string name="no_backup_image_wallpaper_label" msgid="6316627676107284851">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎Rotating Image Wallpaper‎‏‎‎‏‎"</string>
+ <string name="permission_needed_explanation" msgid="139166837541426823">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎To display the current wallpaper here, ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ needs access to your device\'s storage.‎‏‎‎‏‎"</string>
+ <string name="permission_needed_explanation_go_to_settings" msgid="3923551582092599609">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎To display the current wallpaper here, Wallpapers needs access to your device’s storage.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎To change this setting, go to the Permissions area of Wallpapers’ app info.‎‏‎‎‏‎"</string>
+ <string name="permission_needed_allow_access_button_label" msgid="1943133660612924306">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‎‎Allow access‎‏‎‎‏‎"</string>
+ <string name="no_backup_image_wallpaper_description" msgid="8303268619408738057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎Live wallpaper service for rotating wallpapers‎‏‎‎‏‎"</string>
+ <string name="daily_refresh_tile_title" msgid="3270456074558525091">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎Daily wallpaper‎‏‎‎‏‎"</string>
+ <string name="daily_refresh_tile_subtitle" msgid="3976682014885446443">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎Tap to turn on‎‏‎‎‏‎"</string>
+ <string name="start_rotation_dialog_body_live_wallpaper_needed" msgid="5132580257563846082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‎‎Wallpaper will change automatically every day. To finish setup, tap &lt;strong&gt;Set wallpaper&lt;/strong&gt; on the next screen.‎‏‎‎‏‎"</string>
+ <string name="start_rotation_dialog_wifi_only_option_message" msgid="3126269859713666225">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎Download future wallpapers on Wi-Fi only‎‏‎‎‏‎"</string>
+ <string name="start_rotation_dialog_continue" msgid="276678987852274872">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎Continue‎‏‎‎‏‎"</string>
+ <string name="start_rotation_progress_message" msgid="7872623873682262083">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‎Downloading first wallpaper…‎‏‎‎‏‎"</string>
+ <string name="start_rotation_error_message" msgid="3053799836719618972">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎Unable to download first wallpaper. Please check your network settings and try again.‎‏‎‎‏‎"</string>
+ <string name="start_rotation_dialog_body" msgid="7903554799046364916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎Wallpaper will change automatically every day‎‏‎‎‏‎"</string>
+ <string name="settings_button_label" msgid="8724734130079207955">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎Settings‎‏‎‎‏‎"</string>
+ <string name="explore" msgid="7468719504199497281">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‎Explore‎‏‎‎‏‎"</string>
+ <string name="next_wallpaper" msgid="3911873152952596232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎Next wallpaper‎‏‎‎‏‎"</string>
+ <string name="wallpaper_disabled_message" msgid="7309484130562148185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎Setting a wallpaper is disabled on this device‎‏‎‎‏‎"</string>
+ <string name="wallpaper_disabled_by_administrator_message" msgid="1551430406714747884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎‎Setting a wallpaper is disabled by your device administrator‎‏‎‎‏‎"</string>
+ <string name="wallpaper_set_successfully_message" msgid="2958998799111688578">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎Wallpaper set successfully‎‏‎‎‏‎"</string>
+ <string name="wallpapers_unavailable_offline_message" msgid="8136405438621689532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎You need an Internet connection to view wallpapers. Please connect and try again.‎‏‎‎‏‎"</string>
+ <string name="currently_set_home_wallpaper_thumbnail" msgid="4022381436821898917">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎Currently set home screen wallpaper thumbnail‎‏‎‎‏‎"</string>
+ <string name="currently_set_lock_wallpaper_thumbnail" msgid="2094209303934569997">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎Currently set lock screen wallpaper thumbnail‎‏‎‎‏‎"</string>
+ <string name="currently_set_wallpaper_thumbnail" msgid="8651887838745545107">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎Currently set wallpaper thumbnail‎‏‎‎‏‎"</string>
+ <string name="wallpaper_thumbnail" msgid="569931475923605974">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎Wallpaper thumbnail‎‏‎‎‏‎"</string>
+ <string name="explore_home_screen" msgid="8756346794535765482">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎Explore home screen wallpaper‎‏‎‎‏‎"</string>
+ <string name="explore_lock_screen" msgid="268938342103703665">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎Explore lock screen wallpaper‎‏‎‎‏‎"</string>
+ <string name="refresh_daily_wallpaper_home_content_description" msgid="2770445044556164259">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎Refresh daily home screen wallpaper‎‏‎‎‏‎"</string>
+ <string name="refresh_daily_wallpaper_content_description" msgid="4362142658237147583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎Refresh daily wallpaper‎‏‎‎‏‎"</string>
+ <string name="refreshing_daily_wallpaper_dialog_message" msgid="1975910873362855761">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎Refreshing daily wallpaper…‎‏‎‎‏‎"</string>
+ <string name="refresh_daily_wallpaper_failed_message" msgid="4749879993812557166">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎Failed to refresh daily wallpaper. Please check your network connection and try again.‎‏‎‎‏‎"</string>
+ <string name="collapse_attribution_panel" msgid="4367971404848122275">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‎Collapse wallpaper info panel‎‏‎‎‏‎"</string>
+ <string name="expand_attribution_panel" msgid="6975094181456095915">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎Expand wallpaper info panel‎‏‎‎‏‎"</string>
+ <string name="on_device_wallpapers_category_title" msgid="805819102071369004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎On-device wallpapers‎‏‎‎‏‎"</string>
+ <string name="on_device_wallpapers_category_title_desktop" msgid="316919420410065369">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎On device‎‏‎‎‏‎"</string>
+ <string name="on_device_wallpaper_title" msgid="5262564748034629524">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎Android wallpaper‎‏‎‎‏‎"</string>
+ <string name="live_wallpapers_category_title" msgid="1814374812192366349">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎Live wallpapers‎‏‎‎‏‎"</string>
+ <string name="my_photos_category_title" msgid="4294567122144565273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎My photos‎‏‎‎‏‎"</string>
+ <string name="my_photos_generic_wallpaper_title" msgid="7002867526154631172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎My photo‎‏‎‎‏‎"</string>
+ <string name="fallback_wallpaper_title" msgid="6154655421012506001">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎Wallpaper‎‏‎‎‏‎"</string>
+ <string name="app_not_found" msgid="4431461707854088231">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎App isn\'t installed.‎‏‎‎‏‎"</string>
+ <string name="center_wallpaper_position" msgid="4166894762352288883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎Center‎‏‎‎‏‎"</string>
+ <string name="center_crop_wallpaper_position" msgid="1681980019815343348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎Center crop‎‏‎‎‏‎"</string>
+ <string name="stretch_wallpaper_position" msgid="5002680983147456935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎Stretch‎‏‎‎‏‎"</string>
+ <string name="preview" msgid="1774602101743861071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎Preview‎‏‎‎‏‎"</string>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 53c95c0..843ff79 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -126,6 +126,7 @@
<dimen name="preview_attribution_pane_description_height">34dp</dimen>
<dimen name="preview_attribution_pane_button_bottom_margin">8dp</dimen>
+ <dimen name="preview_gradient_background_height">256dp</dimen>
<!-- Dimensions for the "start rotation" dialog. -->
<dimen name="start_rotation_dialog_subhead_margin_top">19dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fe99050..0201f96 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -300,4 +300,19 @@
<!-- Label for a checkbox which lets user preview the displayed image as wallpaper. [CHAR LIMIT=30] -->
<string name="preview">Preview</string>
+
+ <!-- Label for the 'Info' tab of view pager in wallpaper preview activity. [CHAR_LIMIT=25] -->
+ <string name="tab_info">Info</string>
+ <!-- Label for the 'Customize' tab of view pager in wallpaper preview activity.
+ [CHAR_LIMIT=25] -->
+ <string name="tab_customize">Customize</string>
+
+ <!-- List item for configuring the current wallpaper [CHAR LIMIT=30] -->
+ <string name="configure_wallpaper">Settings…</string>
+
+ <!-- List item for deleting the current wallpaper [CHAR LIMIT=30] -->
+ <string name="delete_live_wallpaper">Delete</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>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6259281..1796b1d 100755
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -111,6 +111,15 @@
</style>
<!-- Preview attribution pane styles -->
+ <style name="WallpaperPicker.BottomPaneStyle" parent="@android:style/Theme.DeviceDefault.Settings">
+ <item name="android:textColorPrimary">@color/material_white_100</item>
+ <item name="android:textColorSecondary">@color/white_70_alpha</item>
+ <item name="tabTextAppearance">@style/WallpaperPicker.Preview.TextAppearance.NoAllCaps</item>
+ <item name="tabIndicatorColor">?android:attr/textColorPrimary</item>
+ <item name="tabGravity">fill</item>
+ <item name="tabMaxWidth">0dp</item>
+ </style>
+
<style name="preview_attribution_pane_title">
<item name="android:textColor">@color/material_white_text</item>
<item name="android:textSize">@dimen/abc_text_size_subhead_material</item>
@@ -121,6 +130,11 @@
<item name="android:textSize">@dimen/abc_text_size_body_2_material</item>
</style>
+ <style name="WallpaperPicker.Preview.TextAppearance.NoAllCaps"
+ parent="@android:style/TextAppearance.DeviceDefault.Widget.TabWidget">
+ <item name="android:textAllCaps">false</item>
+ </style>
+
<!-- Set wallpaper destination item -->
<style name="set_wallpaper_destination_item">
<item name="android:minHeight">@dimen/set_wallpaper_dialog_item_min_height</item>
diff --git a/src/com/android/wallpaper/model/CurrentWallpaperInfoV16.java b/src/com/android/wallpaper/model/CurrentWallpaperInfoV16.java
deleted file mode 100755
index 3db46e7..0000000
--- a/src/com/android/wallpaper/model/CurrentWallpaperInfoV16.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2017 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.Activity;
-import android.content.Context;
-import android.os.Parcel;
-
-import com.android.wallpaper.asset.Asset;
-import com.android.wallpaper.asset.CurrentWallpaperAssetV16;
-import com.android.wallpaper.asset.FileAsset;
-import com.android.wallpaper.module.InjectorProvider;
-import com.android.wallpaper.module.NoBackupImageWallpaper;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import androidx.annotation.DrawableRes;
-import androidx.annotation.StringRes;
-
-/**
- * Represents the wallpaper currently set to the device for API 16 through 23. Should not be used
- * to set a new wallpaper.
- */
-public class CurrentWallpaperInfoV16 extends WallpaperInfo {
-
- public static final Creator<CurrentWallpaperInfoV16> CREATOR =
- new Creator<CurrentWallpaperInfoV16>() {
- @Override
- public CurrentWallpaperInfoV16 createFromParcel(Parcel source) {
- return new CurrentWallpaperInfoV16(source);
- }
-
- @Override
- public CurrentWallpaperInfoV16[] newArray(int size) {
- return new CurrentWallpaperInfoV16[size];
- }
- };
- private List<String> mAttributions;
- private Asset mAsset;
- private String mActionUrl;
- @StringRes
- private int mActionLabelRes;
- @DrawableRes
- private int mActionIconRes;
- private String mCollectionId;
-
- public CurrentWallpaperInfoV16(List<String> attributions, String actionUrl,
- @StringRes int actionLabelRes, @DrawableRes int actionIconRes,
- String collectionId) {
- mAttributions = attributions;
- mActionUrl = actionUrl;
- mActionLabelRes = actionLabelRes;
- mActionIconRes = actionIconRes;
- mCollectionId = collectionId;
- }
-
- private CurrentWallpaperInfoV16(Parcel in) {
- mAttributions = new ArrayList<>();
- in.readStringList(mAttributions);
- mActionUrl = in.readString();
- mCollectionId = in.readString();
- mActionLabelRes = in.readInt();
- mActionIconRes = in.readInt();
- }
-
- @Override
- public List<String> getAttributions(Context context) {
- return mAttributions;
- }
-
- @Override
- public Asset getAsset(Context context) {
- if (mAsset == null) {
- boolean isNoBackupImageWallpaperSet = InjectorProvider.getInjector()
- .getLiveWallpaperStatusChecker(context).isNoBackupImageWallpaperSet();
-
- mAsset = isNoBackupImageWallpaperSet
- ? new FileAsset(new File(context.getApplicationContext().getFilesDir(),
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH))
- : new CurrentWallpaperAssetV16(context);
- }
- return mAsset;
- }
-
- @Override
- public Asset getThumbAsset(Context context) {
- return getAsset(context);
- }
-
- @Override
- public String getActionUrl(Context unused) {
- return mActionUrl;
- }
-
- @Override
- public int getActionIconRes(Context unused) {
- return mActionIconRes != 0 ? mActionIconRes : WallpaperInfo.getDefaultActionIcon();
- }
-
- @Override
- public int getActionLabelRes(Context unused) {
- return mActionLabelRes != 0 ? mActionLabelRes : WallpaperInfo.getDefaultActionLabel();
- }
-
- @Override
- public String getCollectionId(Context unused) {
- return mCollectionId;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeStringList(mAttributions);
- parcel.writeString(mActionUrl);
- parcel.writeString(mCollectionId);
- parcel.writeInt(mActionLabelRes);
- parcel.writeInt(mActionIconRes);
- }
-
- @Override
- public void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory,
- int requestCode) {
- srcActivity.startActivityForResult(factory.newIntent(srcActivity, this), requestCode);
- }
-}
diff --git a/src/com/android/wallpaper/model/CurrentWallpaperInfoVN.java b/src/com/android/wallpaper/model/CurrentWallpaperInfoVN.java
index e44e717..bf54bfd 100755
--- a/src/com/android/wallpaper/model/CurrentWallpaperInfoVN.java
+++ b/src/com/android/wallpaper/model/CurrentWallpaperInfoVN.java
@@ -27,13 +27,10 @@ import androidx.annotation.StringRes;
import com.android.wallpaper.asset.Asset;
import com.android.wallpaper.asset.BuiltInWallpaperAsset;
import com.android.wallpaper.asset.CurrentWallpaperAssetVN;
-import com.android.wallpaper.asset.FileAsset;
import com.android.wallpaper.compat.WallpaperManagerCompat;
import com.android.wallpaper.compat.WallpaperManagerCompat.WallpaperLocation;
import com.android.wallpaper.module.InjectorProvider;
-import com.android.wallpaper.module.NoBackupImageWallpaper;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -142,17 +139,6 @@ public class CurrentWallpaperInfoVN extends WallpaperInfo {
* Constructs and returns an Asset instance representing the currently-set wallpaper asset.
*/
private Asset createCurrentWallpaperAssetVN(Context context) {
- // If the live wallpaper for rotating wallpapers is set, then provide a file asset
- // representing that wallpaper.
- boolean isNoBackupImageWallpaperSet = InjectorProvider.getInjector()
- .getLiveWallpaperStatusChecker(context).isNoBackupImageWallpaperSet();
- if (mWallpaperManagerFlag == WallpaperManagerCompat.FLAG_SYSTEM
- && isNoBackupImageWallpaperSet) {
- Context deviceProtectedContext = context.createDeviceProtectedStorageContext();
- return new FileAsset(new File(deviceProtectedContext.getFilesDir(),
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH));
- }
-
WallpaperManagerCompat wallpaperManagerCompat = InjectorProvider.getInjector()
.getWallpaperManagerCompat(context);
diff --git a/src/com/android/wallpaper/model/InlinePreviewIntentFactory.java b/src/com/android/wallpaper/model/InlinePreviewIntentFactory.java
index ce29761..28062d8 100755
--- a/src/com/android/wallpaper/model/InlinePreviewIntentFactory.java
+++ b/src/com/android/wallpaper/model/InlinePreviewIntentFactory.java
@@ -23,6 +23,16 @@ import android.content.Intent;
* wallpaper, if appropriate for that wallpaper.
*/
public interface InlinePreviewIntentFactory {
+
+ /**
+ * @return whether it's possible to use the internal live picker, or {@code false} to use the
+ * the Framework Activity.
+ */
+ default boolean shouldUseInternalLivePicker(Context context) {
+ return false; // Disable always for now
+ // ContextCompat.checkSelfPermission(context, BIND_WALLPAPER) == PERMISSION_GRANTED;
+ }
+
/**
* Gets an intent to show the preview activity for the given wallpaper.
*
@@ -30,5 +40,5 @@ public interface InlinePreviewIntentFactory {
* @param wallpaper
* @return Intent to show the inline preview activity.
*/
- public Intent newIntent(Context ctx, WallpaperInfo wallpaper);
+ Intent newIntent(Context ctx, WallpaperInfo wallpaper);
}
diff --git a/src/com/android/wallpaper/model/LiveWallpaperInfo.java b/src/com/android/wallpaper/model/LiveWallpaperInfo.java
index a408aed..4337230 100755
--- a/src/com/android/wallpaper/model/LiveWallpaperInfo.java
+++ b/src/com/android/wallpaper/model/LiveWallpaperInfo.java
@@ -245,7 +245,7 @@ public class LiveWallpaperInfo extends WallpaperInfo {
return wallpaperInfos;
}
- static boolean isSystemApp(ApplicationInfo appInfo) {
+ private static boolean isSystemApp(ApplicationInfo appInfo) {
return (appInfo.flags & (ApplicationInfo.FLAG_SYSTEM
| ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
}
@@ -262,11 +262,12 @@ public class LiveWallpaperInfo extends WallpaperInfo {
@Override
public List<String> getAttributions(Context context) {
List<String> attributions = new ArrayList<>();
- CharSequence labelCharSeq = mInfo.loadLabel(context.getPackageManager());
+ PackageManager packageManager = context.getPackageManager();
+ CharSequence labelCharSeq = mInfo.loadLabel(packageManager);
attributions.add(labelCharSeq == null ? null : labelCharSeq.toString());
try {
- CharSequence authorCharSeq = mInfo.loadAuthor(context.getPackageManager());
+ CharSequence authorCharSeq = mInfo.loadAuthor(packageManager);
if (authorCharSeq != null) {
String author = authorCharSeq.toString();
attributions.add(author);
@@ -275,6 +276,16 @@ public class LiveWallpaperInfo extends WallpaperInfo {
// No author specified, so no other attribution to add.
}
+ try {
+ CharSequence descCharSeq = mInfo.loadDescription(packageManager);
+ if (descCharSeq != null) {
+ String desc = descCharSeq.toString();
+ attributions.add(desc);
+ }
+ } catch (Resources.NotFoundException e) {
+ // No description specified, so no other attribution to add.
+ }
+
return attributions;
}
@@ -294,6 +305,18 @@ public class LiveWallpaperInfo extends WallpaperInfo {
return null;
}
+ /**
+ * Get an optional description for the action button if provided by this LiveWallpaper.
+ */
+ @Nullable
+ public CharSequence getActionDescription(Context context) {
+ try {
+ return mInfo.loadContextDescription(context.getPackageManager());
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+ }
+
@Override
public Asset getAsset(Context context) {
return null;
@@ -310,9 +333,14 @@ public class LiveWallpaperInfo extends WallpaperInfo {
@Override
public void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory,
int requestCode) {
- Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
- preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, mInfo.getComponent());
- ActivityUtils.startActivityForResultSafely(srcActivity, preview, requestCode);
+ //Only use internal live picker if available, otherwise, default to the Framework one
+ if (factory.shouldUseInternalLivePicker(srcActivity)) {
+ srcActivity.startActivityForResult(factory.newIntent(srcActivity, this), requestCode);
+ } else {
+ Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
+ preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, mInfo.getComponent());
+ ActivityUtils.startActivityForResultSafely(srcActivity, preview, requestCode);
+ }
}
@Override
diff --git a/src/com/android/wallpaper/model/WallpaperRotationInitializer.java b/src/com/android/wallpaper/model/WallpaperRotationInitializer.java
index ad9eef9..5797650 100755
--- a/src/com/android/wallpaper/model/WallpaperRotationInitializer.java
+++ b/src/com/android/wallpaper/model/WallpaperRotationInitializer.java
@@ -58,13 +58,6 @@ public interface WallpaperRotationInitializer extends Parcelable {
Listener listener);
/**
- * Returns whether the live wallpaper needs to be set to the device in order to be able to start
- * rotation or is already set but on home-only on N-MR2 or later, which means the user has the
- * option to pick a new destination preference.
- */
- boolean isNoBackupImageWallpaperPreviewNeeded(Context appContext);
-
- /**
* Gets the current state of the possible wallpaper rotation represented by this object.
*/
void fetchRotationInitializationState(Context context, RotationStateListener listener);
diff --git a/src/com/android/wallpaper/module/BaseWallpaperInjector.java b/src/com/android/wallpaper/module/BaseWallpaperInjector.java
index f8191fc..de9ddb1 100755
--- a/src/com/android/wallpaper/module/BaseWallpaperInjector.java
+++ b/src/com/android/wallpaper/module/BaseWallpaperInjector.java
@@ -34,12 +34,10 @@ public abstract class BaseWallpaperInjector implements Injector {
private Requester mRequester;
private WallpaperManagerCompat mWallpaperManagerCompat;
private CurrentWallpaperInfoFactory mCurrentWallpaperFactory;
- private LiveWallpaperStatusChecker mLiveWallpaperStatusChecker;
private NetworkStatusNotifier mNetworkStatusNotifier;
private AlarmManagerWrapper mAlarmManagerWrapper;
private ExploreIntentChecker mExploreIntentChecker;
private SystemFeatureChecker mSystemFeatureChecker;
- private RotatingWallpaperComponentChecker mRotatingWallpaperComponentChecker;
private FormFactorChecker mFormFactorChecker;
private PackageStatusNotifier mPackageStatusNotifier;
private LiveWallpaperInfoFactory mLiveWallpaperInfoFactory;
@@ -111,15 +109,6 @@ public abstract class BaseWallpaperInjector implements Injector {
}
@Override
- public synchronized LiveWallpaperStatusChecker getLiveWallpaperStatusChecker(Context context) {
- if (mLiveWallpaperStatusChecker == null) {
- mLiveWallpaperStatusChecker =
- new DefaultLiveWallpaperStatusChecker(context.getApplicationContext());
- }
- return mLiveWallpaperStatusChecker;
- }
-
- @Override
public synchronized NetworkStatusNotifier getNetworkStatusNotifier(Context context) {
if (mNetworkStatusNotifier == null) {
mNetworkStatusNotifier = new DefaultNetworkStatusNotifier(context.getApplicationContext());
@@ -161,14 +150,6 @@ public abstract class BaseWallpaperInjector implements Injector {
}
@Override
- public synchronized RotatingWallpaperComponentChecker getRotatingWallpaperComponentChecker() {
- if (mRotatingWallpaperComponentChecker == null) {
- mRotatingWallpaperComponentChecker = new DefaultRotatingWallpaperComponentChecker();
- }
- return mRotatingWallpaperComponentChecker;
- }
-
- @Override
public synchronized FormFactorChecker getFormFactorChecker(Context context) {
if (mFormFactorChecker == null) {
mFormFactorChecker = new DefaultFormFactorChecker(context.getApplicationContext());
diff --git a/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java b/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java
index c74f9b2..dbe3722 100755
--- a/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java
+++ b/src/com/android/wallpaper/module/DefaultCurrentWallpaperInfoFactory.java
@@ -17,16 +17,13 @@ package com.android.wallpaper.module;
import android.content.Context;
-import com.android.wallpaper.compat.BuildCompat;
+import androidx.annotation.Nullable;
+
import com.android.wallpaper.compat.WallpaperManagerCompat;
-import com.android.wallpaper.model.CurrentWallpaperInfoV16;
import com.android.wallpaper.model.CurrentWallpaperInfoVN;
-import com.android.wallpaper.model.LiveWallpaperInfo;
import com.android.wallpaper.model.WallpaperInfo;
import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
-import androidx.annotation.Nullable;
-
/**
* Default implementation of {@link CurrentWallpaperInfoFactory} which actually constructs
* {@link WallpaperInfo} instances representing the wallpapers currently set to the device.
@@ -35,7 +32,6 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF
private final Context mAppContext;
private final WallpaperRefresher mWallpaperRefresher;
- private final LiveWallpaperStatusChecker mLiveWallpaperStatusChecker;
private final LiveWallpaperInfoFactory mLiveWallpaperInfoFactory;
// Cached copies of the currently-set WallpaperInfo(s) and presentation mode.
@@ -49,8 +45,6 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF
mAppContext = context.getApplicationContext();
Injector injector = InjectorProvider.getInjector();
mWallpaperRefresher = injector.getWallpaperRefresher(mAppContext);
- mLiveWallpaperStatusChecker =
- injector.getLiveWallpaperStatusChecker(mAppContext);
mLiveWallpaperInfoFactory = injector.getLiveWallpaperInfoFactory(mAppContext);
}
@@ -72,29 +66,16 @@ public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoF
mWallpaperRefresher.refresh(
(homeWallpaperMetadata, lockWallpaperMetadata, presentationMode) -> {
-
WallpaperInfo homeWallpaper;
-
- if (homeWallpaperMetadata.getWallpaperComponent() == null
- || mLiveWallpaperStatusChecker.isNoBackupImageWallpaperSet()) {
- // Image wallpaper
- if (BuildCompat.isAtLeastN()) {
- homeWallpaper = new CurrentWallpaperInfoVN(
- homeWallpaperMetadata.getAttributions(),
- homeWallpaperMetadata.getActionUrl(),
- homeWallpaperMetadata.getActionLabelRes(),
- homeWallpaperMetadata.getActionIconRes(),
- homeWallpaperMetadata.getCollectionId(),
- WallpaperManagerCompat.FLAG_SYSTEM);
- } else {
- homeWallpaper = new CurrentWallpaperInfoV16(
- homeWallpaperMetadata.getAttributions(),
- homeWallpaperMetadata.getActionUrl(),
- homeWallpaperMetadata.getActionLabelRes(),
- homeWallpaperMetadata.getActionIconRes(),
- homeWallpaperMetadata.getCollectionId());
- }
- } else { // Live wallpaper
+ if (homeWallpaperMetadata.getWallpaperComponent() == null) {
+ homeWallpaper = new CurrentWallpaperInfoVN(
+ homeWallpaperMetadata.getAttributions(),
+ homeWallpaperMetadata.getActionUrl(),
+ homeWallpaperMetadata.getActionLabelRes(),
+ homeWallpaperMetadata.getActionIconRes(),
+ homeWallpaperMetadata.getCollectionId(),
+ WallpaperManagerCompat.FLAG_SYSTEM);
+ } else {
homeWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo(
homeWallpaperMetadata.getWallpaperComponent());
}
diff --git a/src/com/android/wallpaper/module/DefaultLiveWallpaperStatusChecker.java b/src/com/android/wallpaper/module/DefaultLiveWallpaperStatusChecker.java
deleted file mode 100755
index 003a06b..0000000
--- a/src/com/android/wallpaper/module/DefaultLiveWallpaperStatusChecker.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.wallpaper.module;
-
-import android.annotation.SuppressLint;
-import android.app.WallpaperManager;
-import android.content.Context;
-
-/**
- * Default implementation of {@link LiveWallpaperStatusChecker}.
- */
-@SuppressLint("ServiceCast")
-public class DefaultLiveWallpaperStatusChecker implements LiveWallpaperStatusChecker {
-
- private WallpaperManager mWallpaperManager;
-
- public DefaultLiveWallpaperStatusChecker(Context context) {
- // Retrieve WallpaperManager using Context#getSystemService instead of
- // WallpaperManager#getInstance so it can be mocked out in test.
- mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
- }
-
- @Override
- public boolean isNoBackupImageWallpaperSet() {
- android.app.WallpaperInfo liveWallpaper = mWallpaperManager.getWallpaperInfo();
- return liveWallpaper != null
- && liveWallpaper.getServiceName().equals(NoBackupImageWallpaper.class.getName());
- }
-}
diff --git a/src/com/android/wallpaper/module/DefaultRotatingWallpaperComponentChecker.java b/src/com/android/wallpaper/module/DefaultRotatingWallpaperComponentChecker.java
deleted file mode 100755
index eddb6bf..0000000
--- a/src/com/android/wallpaper/module/DefaultRotatingWallpaperComponentChecker.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.wallpaper.module;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-/**
- * Default implementation of {@link RotatingWallpaperComponentChecker}.
- */
-public class DefaultRotatingWallpaperComponentChecker implements RotatingWallpaperComponentChecker {
-
- private static boolean isLiveWallpaperSupported(Context context) {
- return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LIVE_WALLPAPER);
- }
-
- @Override
- @RotatingWallpaperComponent
- public int getCurrentRotatingWallpaperComponent(Context context) {
- if (!isLiveWallpaperSupported(context)) {
- return ROTATING_WALLPAPER_COMPONENT_STATIC;
- }
-
- // If presentation mode is ROTATING but the live wallpaper is not set, then "legacy" rotation
- // from older APKs is in effect and the current rotating wallpaper component is a static WP.
- Injector injector = InjectorProvider.getInjector();
- WallpaperPreferences preferences = injector.getPreferences(context);
- LiveWallpaperStatusChecker liveWallpaperStatusChecker = injector
- .getLiveWallpaperStatusChecker(context);
- if (preferences.getWallpaperPresentationMode()
- == WallpaperPreferences.PRESENTATION_MODE_ROTATING
- && !liveWallpaperStatusChecker.isNoBackupImageWallpaperSet()) {
- return ROTATING_WALLPAPER_COMPONENT_STATIC;
- }
-
- return ROTATING_WALLPAPER_COMPONENT_LIVE;
- }
-
- @Override
- @RotatingWallpaperComponent
- public int getNextRotatingWallpaperComponent(Context context) {
- if (!isLiveWallpaperSupported(context)) {
- return ROTATING_WALLPAPER_COMPONENT_STATIC;
- }
-
- return ROTATING_WALLPAPER_COMPONENT_LIVE;
- }
-
- @Override
- @RotatingWallpaperSupport
- public int getRotatingWallpaperSupport(Context context) {
- FormFactorChecker formFactorChecker =
- InjectorProvider.getInjector().getFormFactorChecker(context);
-
- if (formFactorChecker.getFormFactor() == FormFactorChecker.FORM_FACTOR_DESKTOP) {
- return ROTATING_WALLPAPER_SUPPORT_SUPPORTED;
- }
-
- // While static daily rotation is supported on desktops, it isn't (yet?) supported on phones.
- // For phones which don't support live wallpapers thus we disallow daily rotation altogether.
- return isLiveWallpaperSupported(context) ? ROTATING_WALLPAPER_SUPPORT_SUPPORTED
- : ROTATING_WALLPAPER_SUPPORT_NOT_SUPPORTED;
- }
-}
diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
index e2c968c..27e4491 100755
--- a/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
+++ b/src/com/android/wallpaper/module/DefaultWallpaperPersister.java
@@ -19,7 +19,6 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.WallpaperManager;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
@@ -32,6 +31,8 @@ import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
+import androidx.annotation.Nullable;
+
import com.android.wallpaper.asset.Asset;
import com.android.wallpaper.asset.Asset.BitmapReceiver;
import com.android.wallpaper.asset.Asset.DimensionsReceiver;
@@ -42,24 +43,16 @@ import com.android.wallpaper.compat.BuildCompat;
import com.android.wallpaper.compat.WallpaperManagerCompat;
import com.android.wallpaper.model.WallpaperInfo;
import com.android.wallpaper.module.BitmapCropper.Callback;
-import com.android.wallpaper.module.RotatingWallpaperComponentChecker.RotatingWallpaperComponent;
import com.android.wallpaper.util.BitmapTransformer;
-import com.android.wallpaper.util.DiskBasedLogger;
-import com.android.wallpaper.util.FileMover;
import com.android.wallpaper.util.ScreenSizeCalculator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-import androidx.annotation.Nullable;
-
/**
* Concrete implementation of WallpaperPersister which actually sets wallpapers to the system via
* the WallpaperManager.
@@ -71,11 +64,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
private final Context mAppContext; // The application's context.
// Context that accesses files in device protected storage
- private final Context mDeviceProtectedContext;
private final WallpaperManager mWallpaperManager;
private final WallpaperManagerCompat mWallpaperManagerCompat;
private final WallpaperPreferences mWallpaperPreferences;
- private final RotatingWallpaperComponentChecker mRotatingWallpaperComponentChecker;
private final WallpaperChangedNotifier mWallpaperChangedNotifier;
private WallpaperInfo mWallpaperInfoInPreview;
@@ -83,21 +74,19 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
@SuppressLint("ServiceCast")
public DefaultWallpaperPersister(Context context) {
mAppContext = context.getApplicationContext();
- mDeviceProtectedContext = mAppContext.createDeviceProtectedStorageContext();
// Retrieve WallpaperManager using Context#getSystemService instead of
// WallpaperManager#getInstance so it can be mocked out in test.
Injector injector = InjectorProvider.getInjector();
mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
mWallpaperManagerCompat = injector.getWallpaperManagerCompat(context);
mWallpaperPreferences = injector.getPreferences(context);
- mRotatingWallpaperComponentChecker = injector.getRotatingWallpaperComponentChecker();
mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
}
@Override
public void setIndividualWallpaper(final WallpaperInfo wallpaper, Asset asset,
- @Nullable Rect cropRect, float scale, @Destination final int destination,
- final SetWallpaperCallback callback) {
+ @Nullable Rect cropRect, float scale, @Destination final int destination,
+ final SetWallpaperCallback callback) {
// Set wallpaper without downscaling directly from an input stream if there's no crop rect
// specified by the caller and the asset is streamable.
if (cropRect == null && asset instanceof StreamableAsset) {
@@ -149,7 +138,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
@Override
public void setIndividualWallpaperWithPosition(Activity activity, WallpaperInfo wallpaper,
- @WallpaperPosition int wallpaperPosition, SetWallpaperCallback callback) {
+ @WallpaperPosition int wallpaperPosition, SetWallpaperCallback callback) {
Display display = ((WindowManager) mAppContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(display);
@@ -164,9 +153,10 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
}
switch (wallpaperPosition) {
- // Crop out screen-sized center portion of the source image if it's larger than the screen
- // in both dimensions. Otherwise, decode the entire bitmap and fill the space around it to
- // fill a new screen-sized bitmap with plain black pixels.
+ // Crop out screen-sized center portion of the source image if it's larger
+ // than the screen
+ // in both dimensions. Otherwise, decode the entire bitmap and fill the space
+ // around it to fill a new screen-sized bitmap with plain black pixels.
case WALLPAPER_POSITION_CENTER:
setIndividualWallpaperWithCenterPosition(
wallpaper, asset, dimensions, screenSize, callback);
@@ -178,19 +168,22 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
wallpaper, asset, dimensions, screenSize, callback);
break;
- // Decode full bitmap sized for screen and stretch it to fill the screen dimensions.
+ // Decode full bitmap sized for screen and stretch it to fill the screen
+ // dimensions.
case WALLPAPER_POSITION_STRETCH:
asset.decodeBitmap(screenSize.x, screenSize.y, new BitmapReceiver() {
@Override
public void onBitmapDecoded(@Nullable Bitmap bitmap) {
- setIndividualWallpaperStretch(wallpaper, bitmap, screenSize /* stretchSize */,
+ setIndividualWallpaperStretch(wallpaper, bitmap,
+ screenSize /* stretchSize */,
WallpaperPersister.DEST_BOTH, callback);
}
});
break;
default:
- Log.e(TAG, "Unsupported wallpaper position option specified: " + wallpaperPosition);
+ Log.e(TAG, "Unsupported wallpaper position option specified: "
+ + wallpaperPosition);
callback.onError(null);
}
}
@@ -208,7 +201,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* @param callback Callback used to notify original caller of wallpaper set operation result.
*/
private void setIndividualWallpaperWithCenterPosition(WallpaperInfo wallpaper, Asset asset,
- Point dimensions, Point screenSize, SetWallpaperCallback callback) {
+ Point dimensions, Point screenSize, SetWallpaperCallback callback) {
if (dimensions.x >= screenSize.x && dimensions.y >= screenSize.y) {
Rect cropRect = new Rect(
(dimensions.x - screenSize.x) / 2,
@@ -218,7 +211,8 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
asset.decodeBitmapRegion(cropRect, screenSize.x, screenSize.y, new BitmapReceiver() {
@Override
public void onBitmapDecoded(@Nullable Bitmap bitmap) {
- setIndividualWallpaper(wallpaper, bitmap, WallpaperPersister.DEST_BOTH, callback);
+ setIndividualWallpaper(wallpaper, bitmap, WallpaperPersister.DEST_BOTH,
+ callback);
}
});
} else {
@@ -249,7 +243,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* @param callback Callback used to notify original caller of wallpaper set operation result.
*/
private void setIndividualWallpaperWithCenterCropPosition(WallpaperInfo wallpaper, Asset asset,
- Point dimensions, Point screenSize, SetWallpaperCallback callback) {
+ Point dimensions, Point screenSize, SetWallpaperCallback callback) {
float scale = Math.max((float) screenSize.x / dimensions.x,
(float) screenSize.y / dimensions.y);
@@ -276,7 +270,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* @param callback Called once the wallpaper was set or if an error occurred.
*/
private void setIndividualWallpaper(WallpaperInfo wallpaper, Bitmap croppedBitmap,
- @Destination int destination, SetWallpaperCallback callback) {
+ @Destination int destination, SetWallpaperCallback callback) {
SetWallpaperTask setWallpaperTask =
new SetWallpaperTask(wallpaper, croppedBitmap, destination, callback);
setWallpaperTask.execute();
@@ -287,15 +281,16 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
*
* @param wallpaper Wallpaper model object.
* @param croppedBitmap Bitmap representing the individual wallpaper image.
- * @param fillSize Specifies the final bitmap size that should be set to WallpaperManager. This
- * final bitmap will show the visible area of the provided bitmap after applying a mask with
- * black background the source bitmap and centering. There may be black borders around the
- * original bitmap if it's smaller than the fillSize in one or both dimensions.
+ * @param fillSize Specifies the final bitmap size that should be set to WallpaperManager.
+ * This final bitmap will show the visible area of the provided bitmap
+ * after applying a mask with black background the source bitmap and
+ * centering. There may be black borders around the original bitmap if
+ * it's smaller than the fillSize in one or both dimensions.
* @param destination The destination - where to set the wallpaper to.
* @param callback Called once the wallpaper was set or if an error occurred.
*/
private void setIndividualWallpaperFill(WallpaperInfo wallpaper, Bitmap croppedBitmap,
- Point fillSize, @Destination int destination, SetWallpaperCallback callback) {
+ Point fillSize, @Destination int destination, SetWallpaperCallback callback) {
SetWallpaperTask setWallpaperTask =
new SetWallpaperTask(wallpaper, croppedBitmap, destination, callback);
setWallpaperTask.setFillSize(fillSize);
@@ -308,13 +303,14 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
*
* @param wallpaper Wallpaper model object.
* @param croppedBitmap Bitmap representing the individual wallpaper image.
- * @param stretchSize Specifies the final size to which the the bitmap should be stretched prior
+ * @param stretchSize Specifies the final size to which the bitmap should be stretched
+ * prior
* to being set to the device.
* @param destination The destination - where to set the wallpaper to.
* @param callback Called once the wallpaper was set or if an error occurred.
*/
private void setIndividualWallpaperStretch(WallpaperInfo wallpaper, Bitmap croppedBitmap,
- Point stretchSize, @Destination int destination, SetWallpaperCallback callback) {
+ Point stretchSize, @Destination int destination, SetWallpaperCallback callback) {
SetWallpaperTask setWallpaperTask =
new SetWallpaperTask(wallpaper, croppedBitmap, destination, callback);
setWallpaperTask.setStretchSize(stretchSize);
@@ -330,7 +326,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* @param callback Called once the wallpaper was set or if an error occurred.
*/
private void setIndividualWallpaper(WallpaperInfo wallpaper, InputStream inputStream,
- @Destination int destination, SetWallpaperCallback callback) {
+ @Destination int destination, SetWallpaperCallback callback) {
SetWallpaperTask setWallpaperTask =
new SetWallpaperTask(wallpaper, inputStream, destination, callback);
setWallpaperTask.execute();
@@ -338,58 +334,31 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
@Override
public boolean setWallpaperInRotation(Bitmap wallpaperBitmap, List<String> attributions,
- int actionLabelRes, int actionIconRes,
- String actionUrl, String collectionId) {
- @RotatingWallpaperComponent int rotatingWallpaperComponent = mRotatingWallpaperComponentChecker
- .getCurrentRotatingWallpaperComponent(mAppContext);
-
- switch (rotatingWallpaperComponent) {
- case RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC:
- return setWallpaperInRotationStatic(wallpaperBitmap, attributions, actionUrl,
- actionLabelRes, actionIconRes, collectionId);
- case RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_LIVE:
- return setWallpaperInRotationLive(wallpaperBitmap, attributions, actionUrl,
- actionLabelRes, actionIconRes, collectionId);
- default:
- Log.e(TAG, "Unknown rotating wallpaper component: " + rotatingWallpaperComponent);
- return false;
- }
+ int actionLabelRes, int actionIconRes, String actionUrl, String collectionId) {
+
+ return setWallpaperInRotationStatic(wallpaperBitmap, attributions, actionUrl,
+ actionLabelRes, actionIconRes, collectionId);
}
@Override
public int setWallpaperBitmapInNextRotation(Bitmap wallpaperBitmap) {
- @RotatingWallpaperComponent int rotatingWallpaperComponent = mRotatingWallpaperComponentChecker
- .getNextRotatingWallpaperComponent(mAppContext);
-
- switch (rotatingWallpaperComponent) {
- case RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC:
- return setWallpaperBitmapInRotationStatic(wallpaperBitmap);
- case RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_LIVE:
- boolean isSuccess = setWallpaperBitmapInRotationLive(wallpaperBitmap, true /* isPreview */);
- return isSuccess ? 1 : 0;
- default:
- Log.e(TAG, "Unknown rotating wallpaper component: " + rotatingWallpaperComponent);
- return 0;
- }
+ return setWallpaperBitmapInRotationStatic(wallpaperBitmap);
}
@Override
public boolean finalizeWallpaperForNextRotation(List<String> attributions, String actionUrl,
- int actionLabelRes, int actionIconRes,
- String collectionId, int wallpaperId) {
- @RotatingWallpaperComponent int rotatingWallpaperComponent =
- mRotatingWallpaperComponentChecker.getNextRotatingWallpaperComponent(mAppContext);
+ int actionLabelRes, int actionIconRes, String collectionId, int wallpaperId) {
return finalizeWallpaperForRotatingComponent(attributions, actionUrl, actionLabelRes,
- actionIconRes, collectionId, wallpaperId, rotatingWallpaperComponent);
+ actionIconRes, collectionId, wallpaperId);
}
/**
- * Sets wallpaper image and attributions when a static wallpaper is responsible for presenting the
+ * Sets wallpaper image and attributions when a static wallpaper is responsible for presenting
+ * the
* current "daily wallpaper".
*/
private boolean setWallpaperInRotationStatic(Bitmap wallpaperBitmap, List<String> attributions,
- String actionUrl, int actionLabelRes,
- int actionIconRes, String collectionId) {
+ String actionUrl, int actionLabelRes, int actionIconRes, String collectionId) {
final int wallpaperId = setWallpaperBitmapInRotationStatic(wallpaperBitmap);
if (wallpaperId == 0) {
@@ -397,8 +366,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
}
return finalizeWallpaperForRotatingComponent(attributions, actionUrl, actionLabelRes,
- actionIconRes, collectionId, wallpaperId,
- RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC);
+ actionIconRes, collectionId, wallpaperId);
}
/**
@@ -413,83 +381,21 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
int actionLabelRes,
int actionIconRes,
String collectionId,
- int wallpaperId,
- @RotatingWallpaperComponent int rotatingWallpaperComponent) {
+ int wallpaperId) {
mWallpaperPreferences.clearHomeWallpaperMetadata();
boolean isLockWallpaperSet = isSeparateLockScreenWallpaperSet();
- // Persist wallpaper IDs if the rotating wallpaper component is static and this device is
- // running Android N or later.
- if (rotatingWallpaperComponent
- == RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC) {
- if (BuildCompat.isAtLeastN()) {
- mWallpaperPreferences.setHomeWallpaperManagerId(wallpaperId);
+ // Persist wallpaper IDs if the rotating wallpaper component
+ mWallpaperPreferences.setHomeWallpaperManagerId(wallpaperId);
- // Only copy over wallpaper ID to lock wallpaper if no explicit lock wallpaper is set (so
- // metadata isn't lost if a user explicitly sets a home-only wallpaper).
- if (!isLockWallpaperSet) {
- mWallpaperPreferences.setLockWallpaperId(wallpaperId);
- }
- } else { // Pre-N but using static component
- // Compute bitmap hash code after setting the wallpaper because JPEG compression has likely
- // changed many pixels' color values. Forget the previously loaded wallpaper bitmap so that
- // WallpaperManager doesn't return the old wallpaper drawable.
- mWallpaperManager.forgetLoadedWallpaper();
- Bitmap bitmap = ((BitmapDrawable) mWallpaperManagerCompat.getDrawable()).getBitmap();
- long bitmapHash = BitmapUtils.generateHashCode(bitmap);
-
- mWallpaperPreferences.setHomeWallpaperHashCode(bitmapHash);
- }
- } else { // Live wallpaper rotating component.
-
- // Copy "preview" JPEG to "rotating" JPEG if the preview file exists.
- File rotatingWallpaper;
- try {
- rotatingWallpaper = moveToDeviceProtectedStorage(
- NoBackupImageWallpaper.PREVIEW_WALLPAPER_FILE_PATH,
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
- } catch (Exception e) {
- DiskBasedLogger.e(
- TAG,
- "Unable to move preview to final file for rotating wallpaper " +
- "file (exception)" + e.toString(),
- mAppContext);
- return false;
- }
- if (rotatingWallpaper == null) {
- rotatingWallpaper = mDeviceProtectedContext.getFileStreamPath(
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
- }
- try {
- FileInputStream fis = new FileInputStream(rotatingWallpaper.getAbsolutePath());
- Bitmap bitmap = BitmapFactory.decodeStream(fis);
- fis.close();
-
- if (bitmap != null) {
- long bitmapHash = BitmapUtils.generateHashCode(bitmap);
- mWallpaperPreferences.setHomeWallpaperHashCode(bitmapHash);
- } else {
- Log.e(TAG, "Unable to decode rotating wallpaper file");
- return false;
- }
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Rotating wallpaper file not found at path: "
- + rotatingWallpaper.getAbsolutePath());
- e.printStackTrace();
- return false;
- } catch (IOException e) {
- Log.e(TAG, "IOException when closing FileInputStream " + e);
- return false;
- }
-
- mWallpaperChangedNotifier.notifyWallpaperChanged();
-
- // Send a broadcast to {@link RotatingWallpaperChangedReceiver} in the :live_wallpaper
- // process so the currently displayed wallpaper updates.
- notifyLiveWallpaperBitmapChanged();
+ // Only copy over wallpaper ID to lock wallpaper if no explicit lock wallpaper is set
+ // (so metadata isn't lost if a user explicitly sets a home-only wallpaper).
+ if (!isLockWallpaperSet) {
+ mWallpaperPreferences.setLockWallpaperId(wallpaperId);
}
+
mWallpaperPreferences.setHomeWallpaperAttributions(attributions);
mWallpaperPreferences.setHomeWallpaperActionUrl(actionUrl);
mWallpaperPreferences.setHomeWallpaperActionLabelRes(actionLabelRes);
@@ -498,11 +404,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperPreferences.setHomeWallpaperBaseImageUrl(null);
mWallpaperPreferences.setHomeWallpaperCollectionId(collectionId);
- // Set metadata to lock screen also when the rotating wallpaper is a static one so if user sets
- // a home screen-only wallpaper later, these attributions will still be available.
- if (rotatingWallpaperComponent
- == RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC
- && !isLockWallpaperSet) {
+ // Set metadata to lock screen also when the rotating wallpaper so if user sets a home
+ // screen-only wallpaper later, these attributions will still be available.
+ if (!isLockWallpaperSet) {
mWallpaperPreferences.setLockWallpaperAttributions(attributions);
mWallpaperPreferences.setLockWallpaperActionUrl(actionUrl);
mWallpaperPreferences.setLockWallpaperActionLabelRes(actionLabelRes);
@@ -514,26 +418,6 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
}
/**
- * Sets wallpaper image and attributions when a live wallpaper is responsible for presenting the
- * current "daily wallpaper".
- */
- private boolean setWallpaperInRotationLive(Bitmap wallpaperBitmap, List<String> attributions,
- String actionUrl, int actionLabelRes,
- int actionIconRes, String collectionId) {
-
- synchronized (RotatingWallpaperLockProvider.getInstance()) {
- if (!setWallpaperBitmapInRotationLive(wallpaperBitmap, false /* isPreview */)) {
- return false;
- }
-
- return finalizeWallpaperForRotatingComponent(attributions, actionUrl, actionLabelRes,
- actionIconRes, collectionId,
- 0 /* wallpaperId */,
- RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_LIVE);
- }
- }
-
- /**
* Sets a wallpaper in rotation as a static wallpaper to the {@link WallpaperManager} with the
* option allowBackup=false to save user data.
*
@@ -553,84 +437,6 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
}
/**
- * Sets a wallpaper in rotation as a live wallpaper. Writes wallpaper bitmap to a file in internal
- * storage and sends a broadcast to the live wallpaper notifying it that rotating wallpaper image
- * data changed.
- *
- * @return whether the set wallpaper operation was successful.
- */
- private boolean setWallpaperBitmapInRotationLive(Bitmap wallpaperBitmap, boolean isPreview) {
- File pendingFile;
- try {
- pendingFile = File.createTempFile("rotating_pending", ".jpg", mAppContext.getFilesDir());
- } catch (IOException e) {
- Log.e(TAG, "Unable to create temp file for rotating wallpaper");
- return false;
- }
-
- FileOutputStream fos;
- try {
- fos = mAppContext.openFileOutput(pendingFile.getName(), Context.MODE_PRIVATE);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Unable to open file output stream for pending rotating wallpaper file");
- return false;
- }
-
- boolean compressedSuccessfully =
- wallpaperBitmap.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, fos);
-
- // Close the file stream.
- try {
- fos.flush();
- fos.close();
- } catch (IOException e) {
- Log.e(TAG, "Unable to close FileOutputStream for pending rotating wallpaper file"
- + " (compress succeeded");
- return false;
- }
-
- if (compressedSuccessfully) {
- // Compressing/writing to disk succeeded, so move the pending file to the final location.
- try {
- if (isPreview) {
- if (!pendingFile.renameTo(mAppContext.getFileStreamPath(
- NoBackupImageWallpaper.PREVIEW_WALLPAPER_FILE_PATH))) {
- return false;
- }
- } else {
- moveToDeviceProtectedStorage(pendingFile.getName(),
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
- }
- } catch (Exception e) {
- Log.e(TAG, "Unable to rename pending to final file for rotating wallpaper file"
- + " (exception)" + e.toString());
- return false;
- }
- } else {
- Log.e(TAG, "Unable to compress the wallpaper bitmap");
-
- // Delete the pending file since compressing/writing the image to disk failed.
- try {
- pendingFile.delete();
- } catch (SecurityException e) {
- Log.e(TAG, "Unable to delete pending rotating wallpaper file");
- return false;
- }
-
- return false;
- }
-
- mWallpaperChangedNotifier.notifyWallpaperChanged();
-
- // Send a broadcast to {@link RotatingWallpaperChangedReceiver} in the :live_wallpaper
- // process so the currently displayed wallpaper updates if the live wallpaper is set to the
- // device.
- notifyLiveWallpaperBitmapChanged();
-
- return true;
- }
-
- /**
* Sets a wallpaper bitmap to the {@link WallpaperManagerCompat}.
*
* @return an integer wallpaper ID. This is an actual wallpaper ID on N and later versions of
@@ -638,7 +444,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* operation was successful and zero if the operation encountered an error.
*/
private int setBitmapToWallpaperManagerCompat(Bitmap wallpaperBitmap, boolean allowBackup,
- int whichWallpaper) {
+ int whichWallpaper) {
ByteArrayOutputStream tmpOut = new ByteArrayOutputStream();
if (wallpaperBitmap.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
try {
@@ -668,9 +474,10 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
}
private int setStreamToWallpaperManagerCompat(InputStream inputStream, boolean allowBackup,
- int whichWallpaper) {
+ int whichWallpaper) {
try {
- return mWallpaperManagerCompat.setStream(inputStream, null, allowBackup, whichWallpaper);
+ return mWallpaperManagerCompat.setStream(inputStream, null, allowBackup,
+ whichWallpaper);
} catch (IOException e) {
return 0;
}
@@ -688,7 +495,8 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperInfoInPreview.getWallpaperComponent();
// If there is no live wallpaper set on the WallpaperManager or it doesn't match the
- // WallpaperInfo which was last previewed, then do nothing and nullify last previewed wallpaper.
+ // WallpaperInfo which was last previewed, then do nothing and nullify last previewed
+ // wallpaper.
if (currentWallpaperComponent == null || previewedWallpaperComponent == null
|| !currentWallpaperComponent.getPackageName()
.equals(previewedWallpaperComponent.getPackageName())) {
@@ -729,9 +537,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperInfoInPreview.getWallpaperComponent();
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
+ // 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));
@@ -744,36 +552,6 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperPreferences.clearDailyRotations();
}
- /**
- * Notifies the :live_wallpaper process that the contents of the rotating live wallpaper bitmap
- * changed.
- */
- private void notifyLiveWallpaperBitmapChanged() {
- Intent intent = new Intent(mAppContext.getPackageName()
- + NoBackupImageWallpaper.ACTION_ROTATING_WALLPAPER_CHANGED);
- // Handled by a runtime-registered receiver in NoBackupImageWallpaper.
- intent.setPackage(mAppContext.getPackageName());
- mAppContext.sendBroadcast(intent);
- }
-
- /**
- * Moves a file from the app's files directory to the device content protected storage
- * directory.
- * @param srcFileName Name of the source file (just the name, no path). It's expected to be
- * located in {@link Context#getFilesDir()} for {@link #mAppContext}
- * @param dstFileName Name of the destination file (just the name, no path), which will be
- * located in {@link Context#getFilesDir()}
- * for {@link #mDeviceProtectedContext}
- * @return a {@link File} corresponding to the moved file in its new location, or null if
- * nothing was moved (because srcFileName didn't exist).
- */
- @Nullable
- private File moveToDeviceProtectedStorage(String srcFileName, String dstFileName)
- throws IOException {
- return FileMover.moveFileBetweenContexts(mAppContext, srcFileName, mDeviceProtectedContext,
- dstFileName);
- }
-
private class SetWallpaperTask extends AsyncTask<Void, Void, Boolean> {
private final WallpaperInfo mWallpaper;
@@ -793,7 +571,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
private Point mStretchSize;
SetWallpaperTask(WallpaperInfo wallpaper, Bitmap bitmap, @Destination int destination,
- WallpaperPersister.SetWallpaperCallback callback) {
+ WallpaperPersister.SetWallpaperCallback callback) {
super();
mWallpaper = wallpaper;
mBitmap = bitmap;
@@ -806,7 +584,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* will close the InputStream once it is done with it.
*/
SetWallpaperTask(WallpaperInfo wallpaper, InputStream stream,
- @Destination int destination, WallpaperPersister.SetWallpaperCallback callback) {
+ @Destination int destination, WallpaperPersister.SetWallpaperCallback callback) {
mWallpaper = wallpaper;
mInputStream = stream;
mDestination = destination;
@@ -815,16 +593,18 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
void setFillSize(Point fillSize) {
if (mStretchSize != null) {
- throw new IllegalArgumentException("Can't pass a fill size option if a stretch size is "
- + "already set.");
+ throw new IllegalArgumentException(
+ "Can't pass a fill size option if a stretch size is "
+ + "already set.");
}
mFillSize = fillSize;
}
void setStretchSize(Point stretchSize) {
if (mFillSize != null) {
- throw new IllegalArgumentException("Can't pass a stretch size option if a fill size is "
- + "already set.");
+ throw new IllegalArgumentException(
+ "Can't pass a stretch size option if a fill size is "
+ + "already set.");
}
mStretchSize = stretchSize;
}
@@ -841,16 +621,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
| WallpaperManagerCompat.FLAG_LOCK;
}
- // NOTE: The rotating wallpaper component must be determined here, _before_ actually setting
- // the bitmap/stream on WallpaperManagerCompat, to ensure that the
- // RotatingWallpaperComponentChecker is doing its check while rotation is still enabled.
- // E.g., if "live wallpaper" is the component, then it needs to check while live wallpaper is
- // still set as the active wallpaper on the device. Otherwise, the checker would see a static
- // wallpaper is currently set and it would return the wrong value.
- @RotatingWallpaperComponent int currentRotatingWallpaperComponent =
- mRotatingWallpaperComponentChecker.getCurrentRotatingWallpaperComponent(mAppContext);
- boolean wasLockWallpaperSet = LockWallpaperStatusChecker.isLockWallpaperSet(mAppContext);
+ boolean wasLockWallpaperSet = LockWallpaperStatusChecker.isLockWallpaperSet(
+ mAppContext);
boolean allowBackup = mWallpaper.getBackupPermission() == WallpaperInfo.BACKUP_ALLOWED;
final int wallpaperId;
@@ -860,15 +633,20 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mBitmap = BitmapTransformer.applyFillTransformation(mBitmap, mFillSize);
}
if (mStretchSize != null) {
- mBitmap = Bitmap.createScaledBitmap(mBitmap, mStretchSize.x, mStretchSize.y, true);
+ mBitmap = Bitmap.createScaledBitmap(mBitmap, mStretchSize.x, mStretchSize.y,
+ true);
}
- wallpaperId = setBitmapToWallpaperManagerCompat(mBitmap, allowBackup, whichWallpaper);
+ wallpaperId = setBitmapToWallpaperManagerCompat(mBitmap, allowBackup,
+ whichWallpaper);
} else if (mInputStream != null) {
- wallpaperId = setStreamToWallpaperManagerCompat(mInputStream, allowBackup, whichWallpaper);
+ wallpaperId = setStreamToWallpaperManagerCompat(mInputStream, allowBackup,
+ whichWallpaper);
} else {
- Log.e(TAG, "Both the wallpaper bitmap and input stream are null so we're unable to set any "
- + "kind of wallpaper here.");
+ Log.e(TAG,
+ "Both the wallpaper bitmap and input stream are null so we're unable to "
+ + "set any "
+ + "kind of wallpaper here.");
wallpaperId = 0;
}
@@ -878,7 +656,7 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
== WallpaperPreferences.PRESENTATION_MODE_ROTATING
&& !wasLockWallpaperSet
&& BuildCompat.isAtLeastN()) {
- copyRotatingWallpaperToLock(currentRotatingWallpaperComponent);
+ copyRotatingWallpaperToLock();
}
setImageWallpaperMetadata(mDestination, wallpaperId);
return true;
@@ -914,12 +692,8 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
* Used to accommodate the case where a user had gone from a home+lock daily rotation to
* selecting a static wallpaper on home-only. The image and metadata that was previously
* rotating is now copied to the lock screen.
- *
- * @param currentRotatingWallpaperComponent The component in which rotating wallpapers were
- * presented.
*/
- private void copyRotatingWallpaperToLock(
- @RotatingWallpaperComponent int currentRotatingWallpaperComponent) {
+ private void copyRotatingWallpaperToLock() {
mWallpaperPreferences.setLockWallpaperAttributions(
mWallpaperPreferences.getHomeWallpaperAttributions());
@@ -935,41 +709,28 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
// Set the lock wallpaper ID to what Android set it to, following its having
// copied the system wallpaper over to the lock screen when we changed from
// "both" to distinct system and lock screen wallpapers.
- if (currentRotatingWallpaperComponent
- == RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_COMPONENT_STATIC) {
- mWallpaperPreferences.setLockWallpaperId(
- mWallpaperManagerCompat.getWallpaperId(WallpaperManagerCompat.FLAG_LOCK));
- } else {
- try {
- FileInputStream fileInputStream = mDeviceProtectedContext.openFileInput(
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
- int lockWallpaperId = setStreamToWallpaperManagerCompat(
- fileInputStream, false /* allowBackup */, WallpaperManagerCompat.FLAG_LOCK);
- fileInputStream.close();
- mWallpaperPreferences.setLockWallpaperId(lockWallpaperId);
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Couldn't copy over previously rotating wallpaper to lock screen.");
- } catch (IOException e) {
- Log.e(TAG, "IOException when closing the file input stream " + e);
- }
- }
+ mWallpaperPreferences.setLockWallpaperId(
+ mWallpaperManagerCompat.getWallpaperId(WallpaperManagerCompat.FLAG_LOCK));
+
}
/**
- * Sets the image wallpaper's metadata on SharedPreferences. This method is called after the set
- * wallpaper operation is successful.
+ * Sets the image wallpaper's metadata on SharedPreferences. This method is called after the
+ * set wallpaper operation is successful.
*
- * @param destination Which destination of wallpaper the metadata corresponds to (home screen,
- * lock screen, or both).
- * @param wallpaperId The ID of the static wallpaper returned by WallpaperManager, which on N
- * and later versions of Android uniquely identifies a wallpaper image.
+ * @param destination Which destination of wallpaper the metadata corresponds to (home
+ * screen, lock screen, or both).
+ * @param wallpaperId The ID of the static wallpaper returned by WallpaperManager, which
+ * on N and later versions of Android uniquely identifies a wallpaper
+ * image.
*/
private void setImageWallpaperMetadata(@Destination int destination, int wallpaperId) {
if (destination == DEST_HOME_SCREEN || destination == DEST_BOTH) {
mWallpaperPreferences.clearHomeWallpaperMetadata();
setImageWallpaperHomeMetadata(wallpaperId);
- // Reset presentation mode to STATIC if an individual wallpaper is set to the home screen
+ // Reset presentation mode to STATIC if an individual wallpaper is set to the
+ // home screen
// because rotation always affects at least the home screen.
mWallpaperPreferences.setWallpaperPresentationMode(
WallpaperPreferences.PRESENTATION_MODE_STATIC);
@@ -988,10 +749,11 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperPreferences.setHomeWallpaperManagerId(homeWallpaperId);
}
- // Compute bitmap hash code after setting the wallpaper because JPEG compression has likely
- // changed many pixels' color values. Forget the previously loaded wallpaper bitmap so that
- // WallpaperManager doesn't return the old wallpaper drawable. Do this on N+ devices in
- // addition to saving the wallpaper ID for the purpose of backup & restore.
+ // Compute bitmap hash code after setting the wallpaper because JPEG compression has
+ // likely changed many pixels' color values. Forget the previously loaded wallpaper
+ // bitmap so that WallpaperManager doesn't return the old wallpaper drawable. Do this
+ // on N+ devices in addition to saving the wallpaper ID for the purpose of backup &
+ // restore.
mWallpaperManager.forgetLoadedWallpaper();
mBitmap = ((BitmapDrawable) mWallpaperManagerCompat.getDrawable()).getBitmap();
long bitmapHash = BitmapUtils.generateHashCode(mBitmap);
@@ -1023,9 +785,10 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
mWallpaperPreferences.setLockWallpaperCollectionId(
mWallpaper.getCollectionId(mAppContext));
- // Save the lock wallpaper image's hash code as well for the sake of backup & restore 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.
+ // Save the lock wallpaper image's hash code as well for the sake of backup & restore
+ // 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();
}
@@ -1051,7 +814,9 @@ public class DefaultWallpaperPersister implements WallpaperPersister {
try {
fileStream.close();
} catch (IOException e) {
- Log.e(TAG, "IO exception when closing the input stream for the lock screen WP.");
+ Log.e(TAG,
+ "IO exception when closing the input stream for the lock screen "
+ + "WP.");
}
}
}
diff --git a/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java b/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java
index 319276b..b040ebb 100755
--- a/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java
+++ b/src/com/android/wallpaper/module/DefaultWallpaperPreferences.java
@@ -24,6 +24,8 @@ import android.util.Log;
import androidx.annotation.Nullable;
+import com.android.wallpaper.module.WallpaperPreferenceKeys.NoBackupKeys;
+
import org.json.JSONArray;
import org.json.JSONException;
@@ -39,10 +41,12 @@ import java.util.List;
*/
public class DefaultWallpaperPreferences implements WallpaperPreferences {
public static final String PREFS_NAME = "wallpaper";
+ public static final String NO_BACKUP_PREFS_NAME = "wallpaper-nobackup";
private static final String TAG = "DefaultWPPreferences";
protected SharedPreferences mSharedPrefs;
+ protected SharedPreferences mNoBackupPrefs;
protected Context mContext;
// Keep a strong reference to this OnSharedPreferenceChangeListener to prevent the listener from
@@ -51,19 +55,106 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
public DefaultWallpaperPreferences(Context context) {
mSharedPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ mNoBackupPrefs = context.getSharedPreferences(NO_BACKUP_PREFS_NAME, Context.MODE_PRIVATE);
+ if (mNoBackupPrefs.getAll().isEmpty() && !mSharedPrefs.getAll().isEmpty()) {
+ upgradePrefs();
+ }
mContext = context.getApplicationContext();
// Register a prefs changed listener so that all prefs changes trigger a backup event.
final BackupManager backupManager = new BackupManager(context);
- mSharedPrefsChangedListener = new OnSharedPreferenceChangeListener() {
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- backupManager.dataChanged();
- }
- };
+ mSharedPrefsChangedListener = (sharedPreferences, key) -> backupManager.dataChanged();
mSharedPrefs.registerOnSharedPreferenceChangeListener(mSharedPrefsChangedListener);
}
+ /**
+ * Move {@link NoBackupKeys} preferences that might have been in mSharedPrefs from previous
+ * versions of the app into mNoBackupPrefs.
+ */
+ private void upgradePrefs() {
+ SharedPreferences.Editor editor = mNoBackupPrefs.edit();
+ if (mSharedPrefs.contains(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL)) {
+ editor.putString(NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL,
+ mSharedPrefs.getString(NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL, null));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID)) {
+ editor.putInt(NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID)) {
+ editor.putString(NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID,
+ mSharedPrefs.getString(NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID, null));
+ }
+ if (mSharedPrefs.contains(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE)) {
+ editor.putString(NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE,
+ mSharedPrefs.getString(NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE, null));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID)) {
+ editor.putInt(NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID, 0));
+ }
+ if (mSharedPrefs.contains(
+ NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE)) {
+ editor.putString(NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE,
+ mSharedPrefs.getString(NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE, null));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS)) {
+ editor.putString(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS,
+ mSharedPrefs.getString(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, null));
+ }
+ if (mSharedPrefs.contains(
+ NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP)) {
+ editor.putLong(NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP,
+ mSharedPrefs.getLong(NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP, -1));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LAST_DAILY_LOG_TIMESTAMP)) {
+ editor.putLong(NoBackupKeys.KEY_LAST_DAILY_LOG_TIMESTAMP,
+ mSharedPrefs.getLong(NoBackupKeys.KEY_LAST_DAILY_LOG_TIMESTAMP, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP)) {
+ editor.putLong(NoBackupKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP,
+ mSharedPrefs.getLong(NoBackupKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LAST_ROTATION_STATUS)) {
+ editor.putInt(NoBackupKeys.KEY_LAST_ROTATION_STATUS,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_LAST_ROTATION_STATUS, -1));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP)) {
+ editor.putLong(NoBackupKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP,
+ mSharedPrefs.getLong(NoBackupKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_LAST_SYNC_TIMESTAMP)) {
+ editor.putLong(NoBackupKeys.KEY_LAST_SYNC_TIMESTAMP,
+ mSharedPrefs.getLong(NoBackupKeys.KEY_LAST_SYNC_TIMESTAMP, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS)) {
+ editor.putInt(NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS,
+ WALLPAPER_SET_NOT_PENDING));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS)) {
+ editor.putInt(NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
+ DAILY_WALLPAPER_UPDATE_NOT_PENDING));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED)) {
+ editor.putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED,
+ mSharedPrefs.getInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED, 0));
+ }
+ if (mSharedPrefs.contains(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED)) {
+ 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));
+ }
+
+ editor.apply();
+ }
+
private int getResIdPersistedByName(String key, String type) {
String resName = mSharedPrefs.getString(key, null);
if (resName == null) {
@@ -106,13 +197,16 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
public void setHomeWallpaperAttributions(List<String> attributions) {
SharedPreferences.Editor editor = mSharedPrefs.edit();
if (attributions.size() > 0) {
- editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_1, attributions.get(0));
+ editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_1,
+ attributions.get(0));
}
if (attributions.size() > 1) {
- editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_2, attributions.get(1));
+ editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_2,
+ attributions.get(1));
}
if (attributions.size() > 2) {
- editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_3, attributions.get(2));
+ editor.putString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ATTRIB_3,
+ attributions.get(2));
}
editor.apply();
}
@@ -155,19 +249,22 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
public String getHomeWallpaperBaseImageUrl() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL, null);
+ return mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL, null);
}
@Override
public void setHomeWallpaperBaseImageUrl(String baseImageUrl) {
- mSharedPrefs.edit().putString(
- WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL, baseImageUrl).apply();
+ mNoBackupPrefs.edit().putString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL, baseImageUrl)
+ .apply();
}
@Override
@Nullable
public String getHomeWallpaperCollectionId() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_COLLECTION_ID, null);
+ return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_COLLECTION_ID,
+ null);
}
@Override
@@ -179,14 +276,14 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
@Nullable
public String getHomeWallpaperBackingFileName() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BACKING_FILE,
- null);
+ return mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE, null);
}
@Override
public void setHomeWallpaperBackingFileName(String fileName) {
- mSharedPrefs.edit().putString(
- WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BACKING_FILE, fileName).apply();
+ mNoBackupPrefs.edit().putString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE, fileName).apply();
}
@Override
@@ -213,47 +310,56 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
.remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ACTION_URL)
.remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ACTION_LABEL_RES)
.remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_ACTION_ICON_RES)
- .remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL)
.remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_HASH_CODE)
- .remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_MANAGER_ID)
- .remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME)
- .remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_REMOTE_ID)
- .remove(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_BACKING_FILE)
+ .apply();
+
+ mNoBackupPrefs.edit()
+ .remove(NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME)
+ .remove(NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID)
+ .remove(NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID)
+ .remove(NoBackupKeys.KEY_HOME_WALLPAPER_BASE_IMAGE_URL)
+ .remove(NoBackupKeys.KEY_HOME_WALLPAPER_BACKING_FILE)
.apply();
}
@Override
public String getHomeWallpaperPackageName() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, null);
+ return mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, null);
}
@Override
public void setHomeWallpaperPackageName(String packageName) {
- mSharedPrefs.edit().putString(
- WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, packageName).apply();
+ mNoBackupPrefs.edit().putString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_PACKAGE_NAME, packageName)
+ .apply();
}
@Override
public int getHomeWallpaperManagerId() {
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_MANAGER_ID, 0);
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID, 0);
}
@Override
public void setHomeWallpaperManagerId(int homeWallpaperId) {
- mSharedPrefs.edit().putInt(
- WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_MANAGER_ID, homeWallpaperId).apply();
+ mNoBackupPrefs.edit().putInt(
+ NoBackupKeys.KEY_HOME_WALLPAPER_MANAGER_ID, homeWallpaperId)
+ .apply();
}
@Nullable
@Override
public String getHomeWallpaperRemoteId() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_REMOTE_ID, null);
+ return mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID, null);
}
@Override
public void setHomeWallpaperRemoteId(@Nullable String wallpaperRemoteId) {
- mSharedPrefs.edit().putString(
- WallpaperPreferenceKeys.KEY_HOME_WALLPAPER_REMOTE_ID, wallpaperRemoteId).apply();
+ mNoBackupPrefs.edit().putString(
+ NoBackupKeys.KEY_HOME_WALLPAPER_REMOTE_ID, wallpaperRemoteId)
+ .apply();
}
@Override
@@ -269,13 +375,16 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
public void setLockWallpaperAttributions(List<String> attributions) {
SharedPreferences.Editor editor = mSharedPrefs.edit();
if (attributions.size() > 0) {
- editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_1, attributions.get(0));
+ editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_1,
+ attributions.get(0));
}
if (attributions.size() > 1) {
- editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_2, attributions.get(1));
+ editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_2,
+ attributions.get(1));
}
if (attributions.size() > 2) {
- editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_3, attributions.get(2));
+ editor.putString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ATTRIB_3,
+ attributions.get(2));
}
editor.apply();
}
@@ -319,7 +428,8 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
@Nullable
public String getLockWallpaperCollectionId() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_COLLECTION_ID, null);
+ return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_COLLECTION_ID,
+ null);
}
@Override
@@ -331,25 +441,27 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
@Nullable
public String getLockWallpaperBackingFileName() {
- return mSharedPrefs.getString(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_BACKING_FILE,
- null);
+ return mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE, null);
}
@Override
public void setLockWallpaperBackingFileName(String fileName) {
- mSharedPrefs.edit().putString(
- WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_BACKING_FILE, fileName).apply();
+ mNoBackupPrefs.edit().putString(
+ NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE, fileName).apply();
}
@Override
public int getLockWallpaperId() {
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_MANAGER_ID, 0);
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID, 0);
}
@Override
public void setLockWallpaperId(int lockWallpaperId) {
- mSharedPrefs.edit().putInt(
- WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_MANAGER_ID, lockWallpaperId).apply();
+ mNoBackupPrefs.edit().putInt(
+ NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID, lockWallpaperId)
+ .apply();
}
@Override
@@ -378,21 +490,25 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
.remove(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ACTION_LABEL_RES)
.remove(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_ACTION_ICON_RES)
.remove(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_HASH_CODE)
- .remove(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_MANAGER_ID)
- .remove(WallpaperPreferenceKeys.KEY_LOCK_WALLPAPER_BACKING_FILE)
+ .apply();
+
+ mNoBackupPrefs.edit()
+ .remove(NoBackupKeys.KEY_LOCK_WALLPAPER_MANAGER_ID)
+ .remove(NoBackupKeys.KEY_LOCK_WALLPAPER_BACKING_FILE)
.apply();
}
@Override
public void addDailyRotation(long timestamp) {
- String jsonString = mSharedPrefs.getString(
- WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
+ String jsonString = mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
try {
JSONArray jsonArray = new JSONArray(jsonString);
jsonArray.put(timestamp);
- mSharedPrefs.edit()
- .putString(WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, jsonArray.toString())
+ mNoBackupPrefs.edit()
+ .putString(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS,
+ jsonArray.toString())
.apply();
} catch (JSONException e) {
Log.e(TAG, "Failed to add a daily rotation timestamp due to a JSON parse exception");
@@ -401,8 +517,8 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
public long getLastDailyRotationTimestamp() {
- String jsonString = mSharedPrefs.getString(
- WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
+ String jsonString = mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
try {
JSONArray jsonArray = new JSONArray(jsonString);
@@ -428,15 +544,15 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
oneWeekAgo.add(Calendar.WEEK_OF_YEAR, -1);
long oneWeekAgoTimestamp = oneWeekAgo.getTimeInMillis();
- // Return null if daily rotation wasn't enabled (timestamp value of -1) or was enabled earlier
- // than one week ago.
+ // Return null if daily rotation wasn't enabled (timestamp value of -1) or was enabled
+ // less than one week ago.
if (enabledTimestamp == -1 || enabledTimestamp > oneWeekAgoTimestamp) {
return null;
}
List<Long> timestamps = new ArrayList<>();
- String jsonString = mSharedPrefs.getString(
- WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
+ String jsonString = mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
try {
JSONArray jsonArray = new JSONArray(jsonString);
@@ -451,8 +567,9 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
}
jsonArray = new JSONArray(timestamps);
- mSharedPrefs.edit()
- .putString(WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, jsonArray.toString())
+ mNoBackupPrefs.edit()
+ .putString(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS,
+ jsonArray.toString())
.apply();
} catch (JSONException e) {
Log.e(TAG, "Failed to get daily rotation timestamps due to a JSON parse exception");
@@ -479,21 +596,21 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
midnightToday.set(Calendar.MINUTE, 0);
long midnightTodayTimestamp = midnightToday.getTimeInMillis();
- // Return null if daily rotation wasn't enabled (timestamp value of -1) or was enabled earlier
- // than midnight yesterday.
+ // Return null if daily rotation wasn't enabled (timestamp value of -1) or was enabled
+ // less than midnight yesterday.
if (enabledTimestamp == -1 || enabledTimestamp > midnightYesterdayTimestamp) {
return null;
}
List<Long> timestamps = new ArrayList<>();
- String jsonString = mSharedPrefs.getString(
- WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
+ String jsonString = mNoBackupPrefs.getString(
+ NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS, "[]");
try {
JSONArray jsonArray = new JSONArray(jsonString);
- // Filter the timestamps (which cover up to one week of data) to only include those between
- // midnight yesterday and midnight today.
+ // Filter the timestamps (which cover up to one week of data) to only include those
+ // between midnight yesterday and midnight today.
for (int i = 0; i < jsonArray.length(); i++) {
long timestamp = jsonArray.getLong(i);
if (timestamp >= midnightYesterdayTimestamp && timestamp < midnightTodayTimestamp) {
@@ -510,160 +627,175 @@ public class DefaultWallpaperPreferences implements WallpaperPreferences {
@Override
public long getDailyWallpaperEnabledTimestamp() {
- return mSharedPrefs.getLong(WallpaperPreferenceKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP, -1);
+ return mNoBackupPrefs.getLong(
+ NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP, -1);
}
@Override
public void setDailyWallpaperEnabledTimestamp(long timestamp) {
- mSharedPrefs.edit()
- .putLong(WallpaperPreferenceKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP, timestamp)
+ mNoBackupPrefs.edit()
+ .putLong(NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP,
+ timestamp)
.apply();
}
@Override
public void clearDailyRotations() {
- mSharedPrefs.edit()
- .remove(WallpaperPreferenceKeys.KEY_DAILY_ROTATION_TIMESTAMPS)
- .remove(WallpaperPreferenceKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP)
+ mNoBackupPrefs.edit()
+ .remove(NoBackupKeys.KEY_DAILY_ROTATION_TIMESTAMPS)
+ .remove(NoBackupKeys.KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP)
.apply();
}
@Override
public long getLastDailyLogTimestamp() {
- return mSharedPrefs.getLong(WallpaperPreferenceKeys.KEY_LAST_DAILY_LOG_TIMESTAMP, 0);
+ return mNoBackupPrefs.getLong(
+ NoBackupKeys.KEY_LAST_DAILY_LOG_TIMESTAMP, 0);
}
@Override
public void setLastDailyLogTimestamp(long timestamp) {
- mSharedPrefs.edit()
- .putLong(WallpaperPreferenceKeys.KEY_LAST_DAILY_LOG_TIMESTAMP, timestamp)
+ mNoBackupPrefs.edit()
+ .putLong(NoBackupKeys.KEY_LAST_DAILY_LOG_TIMESTAMP, timestamp)
.apply();
}
@Override
public long getLastAppActiveTimestamp() {
- return mSharedPrefs.getLong(WallpaperPreferenceKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP, 0);
+ return mNoBackupPrefs.getLong(
+ NoBackupKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP, 0);
}
@Override
public void setLastAppActiveTimestamp(long timestamp) {
- mSharedPrefs.edit()
- .putLong(WallpaperPreferenceKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP, timestamp)
+ mNoBackupPrefs.edit()
+ .putLong(NoBackupKeys.KEY_LAST_APP_ACTIVE_TIMESTAMP, timestamp)
.apply();
}
@Override
public void setDailyWallpaperRotationStatus(int status, long timestamp) {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_LAST_ROTATION_STATUS, status)
- .putLong(WallpaperPreferenceKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP, timestamp)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_LAST_ROTATION_STATUS, status)
+ .putLong(NoBackupKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP,
+ timestamp)
.apply();
}
@Override
public int getDailyWallpaperLastRotationStatus() {
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_LAST_ROTATION_STATUS, -1);
+ return mNoBackupPrefs.getInt(NoBackupKeys.KEY_LAST_ROTATION_STATUS, -1);
}
@Override
public long getDailyWallpaperLastRotationStatusTimestamp() {
- return mSharedPrefs.getLong(WallpaperPreferenceKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP, 0);
+ return mNoBackupPrefs.getLong(
+ NoBackupKeys.KEY_LAST_ROTATION_STATUS_TIMESTAMP, 0);
}
@Override
public long getLastSyncTimestamp() {
- return mSharedPrefs.getLong(WallpaperPreferenceKeys.KEY_LAST_SYNC_TIMESTAMP, 0);
+ return mNoBackupPrefs.getLong(NoBackupKeys.KEY_LAST_SYNC_TIMESTAMP, 0);
}
@Override
public void setLastSyncTimestamp(long timestamp) {
- // Write synchronously via commit() to ensure this timetsamp gets written to disk immediately.
- mSharedPrefs.edit()
- .putLong(WallpaperPreferenceKeys.KEY_LAST_SYNC_TIMESTAMP, timestamp)
+ // Write synchronously via commit() to ensure this timetsamp gets written to disk
+ // immediately.
+ mNoBackupPrefs.edit()
+ .putLong(NoBackupKeys.KEY_LAST_SYNC_TIMESTAMP, timestamp)
.commit();
}
@Override
public void setPendingWallpaperSetStatusSync(@PendingWallpaperSetStatus int setStatus) {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_PENDING_WALLPAPER_SET_STATUS, setStatus)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS,
+ setStatus)
.commit();
}
@Override
public int getPendingWallpaperSetStatus() {
//noinspection ResourceType
- return mSharedPrefs.getInt(
- WallpaperPreferenceKeys.KEY_PENDING_WALLPAPER_SET_STATUS, WALLPAPER_SET_NOT_PENDING);
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS,
+ WALLPAPER_SET_NOT_PENDING);
}
@Override
public void setPendingWallpaperSetStatus(@PendingWallpaperSetStatus int setStatus) {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_PENDING_WALLPAPER_SET_STATUS, setStatus)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_PENDING_WALLPAPER_SET_STATUS,
+ setStatus)
.apply();
}
@Override
public void setPendingDailyWallpaperUpdateStatusSync(
@PendingDailyWallpaperUpdateStatus int updateStatus) {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS, updateStatus)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
+ updateStatus)
.commit();
}
@Override
public int getPendingDailyWallpaperUpdateStatus() {
//noinspection ResourceType
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
DAILY_WALLPAPER_UPDATE_NOT_PENDING);
}
@Override
public void setPendingDailyWallpaperUpdateStatus(
@PendingDailyWallpaperUpdateStatus int updateStatus) {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS, updateStatus)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS,
+ updateStatus)
.apply();
}
@Override
public void incrementNumDaysDailyRotationFailed() {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED,
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED,
getNumDaysDailyRotationFailed() + 1)
.apply();
}
@Override
public int getNumDaysDailyRotationFailed() {
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED, 0);
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED, 0);
}
@Override
public void resetNumDaysDailyRotationFailed() {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED, 0)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_FAILED, 0)
.apply();
}
@Override
public void incrementNumDaysDailyRotationNotAttempted() {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED,
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED,
getNumDaysDailyRotationNotAttempted() + 1)
.apply();
}
@Override
public int getNumDaysDailyRotationNotAttempted() {
- return mSharedPrefs.getInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, 0);
+ return mNoBackupPrefs.getInt(
+ NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, 0);
}
@Override
public void resetNumDaysDailyRotationNotAttempted() {
- mSharedPrefs.edit()
- .putInt(WallpaperPreferenceKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, 0)
+ mNoBackupPrefs.edit()
+ .putInt(NoBackupKeys.KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED, 0)
.apply();
}
}
diff --git a/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java b/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java
index c97d2b9..d85e04e 100755
--- a/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java
+++ b/src/com/android/wallpaper/module/DefaultWallpaperRefresher.java
@@ -32,7 +32,6 @@ import com.android.wallpaper.compat.WallpaperManagerCompat;
import com.android.wallpaper.model.WallpaperMetadata;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -50,9 +49,6 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher {
private final Context mAppContext;
private final WallpaperPreferences mWallpaperPreferences;
private final WallpaperManager mWallpaperManager;
- private final LiveWallpaperStatusChecker mLiveWallpaperStatusChecker;
- private final UserEventLogger mUserEventLogger;
- private final Context mDeviceProtectedContext;
/**
* @param context The application's context.
@@ -62,13 +58,10 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher {
Injector injector = InjectorProvider.getInjector();
mWallpaperPreferences = injector.getPreferences(mAppContext);
- mLiveWallpaperStatusChecker = injector.getLiveWallpaperStatusChecker(mAppContext);
- mUserEventLogger = injector.getUserEventLogger(mAppContext);
// Retrieve WallpaperManager using Context#getSystemService instead of
// WallpaperManager#getInstance so it can be mocked out in test.
mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
- mDeviceProtectedContext = mAppContext.createDeviceProtectedStorageContext();
}
@Override
@@ -203,8 +196,7 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher {
* current system wallpaper.
*/
private boolean isHomeScreenMetadataCurrent() {
- return (mWallpaperManager.getWallpaperInfo() == null
- || mLiveWallpaperStatusChecker.isNoBackupImageWallpaperSet())
+ return (mWallpaperManager.getWallpaperInfo() == null)
? isHomeScreenImageWallpaperCurrent()
: isHomeScreenLiveWallpaperCurrent();
}
@@ -221,36 +213,6 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher {
private long getCurrentHomeWallpaperHashCode() {
if (mCurrentHomeWallpaperHashCode == 0) {
- if (mLiveWallpaperStatusChecker.isNoBackupImageWallpaperSet()) {
-
- synchronized (RotatingWallpaperLockProvider.getInstance()) {
- Bitmap bitmap = null;
- try {
- FileInputStream fis =
- mDeviceProtectedContext.openFileInput(
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
- bitmap = BitmapFactory.decodeStream(fis);
- fis.close();
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Rotating wallpaper file not found at path: "
- + mDeviceProtectedContext.getFileStreamPath(
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH),
- e);
- } catch (IOException e) {
- Log.e(TAG, "IOException when closing FileInputStream " + e);
- }
-
- if (bitmap != null) {
- mCurrentHomeWallpaperHashCode = BitmapUtils.generateHashCode(bitmap);
- mUserEventLogger.logDailyWallpaperDecodes(true);
- } else {
- // If an error occurred decoding the stream then we should just assume the current
- // home wallpaper remained intact.
- mCurrentHomeWallpaperHashCode = mWallpaperPreferences.getHomeWallpaperHashCode();
- mUserEventLogger.logDailyWallpaperDecodes(false);
- }
- }
- } else {
BitmapDrawable wallpaperDrawable = (BitmapDrawable) mWallpaperManagerCompat.getDrawable();
Bitmap wallpaperBitmap = wallpaperDrawable.getBitmap();
mCurrentHomeWallpaperHashCode = BitmapUtils.generateHashCode(wallpaperBitmap);
@@ -258,7 +220,6 @@ public class DefaultWallpaperRefresher implements WallpaperRefresher {
// 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;
}
diff --git a/src/com/android/wallpaper/module/Injector.java b/src/com/android/wallpaper/module/Injector.java
index 3afaeb4..ca64b9d 100755
--- a/src/com/android/wallpaper/module/Injector.java
+++ b/src/com/android/wallpaper/module/Injector.java
@@ -44,8 +44,6 @@ public interface Injector {
FormFactorChecker getFormFactorChecker(Context context);
- LiveWallpaperStatusChecker getLiveWallpaperStatusChecker(Context context);
-
LoggingOptInStatusProvider getLoggingOptInStatusProvider(Context context);
NetworkStatusNotifier getNetworkStatusNotifier(Context context);
@@ -56,8 +54,6 @@ public interface Injector {
Requester getRequester(Context context);
- RotatingWallpaperComponentChecker getRotatingWallpaperComponentChecker();
-
SystemFeatureChecker getSystemFeatureChecker();
UserEventLogger getUserEventLogger(Context context);
diff --git a/src/com/android/wallpaper/module/NoBackupImageWallpaper.java b/src/com/android/wallpaper/module/NoBackupImageWallpaper.java
deleted file mode 100755
index a76d881..0000000
--- a/src/com/android/wallpaper/module/NoBackupImageWallpaper.java
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.wallpaper.module;
-
-import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
-import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
-
-import android.annotation.SuppressLint;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks2;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.opengl.GLES20;
-import android.opengl.GLUtils;
-import android.os.AsyncTask;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Handler;
-import android.renderscript.Matrix4f;
-import android.service.wallpaper.WallpaperService;
-import android.util.Log;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.WindowManager;
-
-import com.android.wallpaper.util.ScreenSizeCalculator;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-
-import androidx.annotation.RequiresApi;
-
-/**
- * Live wallpaper service which simply renders a wallpaper from internal storage. Designed as a
- * workaround to WallpaperManager not having an allowBackup=false option on pre-N builds of Android.
- * <p>
- * Adapted from {@code com.android.systemui.ImageWallpaper}.
- */
-@SuppressLint("ServiceCast")
-public class NoBackupImageWallpaper extends WallpaperService {
-
- public static final String ACTION_ROTATING_WALLPAPER_CHANGED =
- ".ACTION_ROTATING_WALLPAPER_CHANGED";
- public static final String PERMISSION_NOTIFY_ROTATING_WALLPAPER_CHANGED =
- ".NOTIFY_ROTATING_WALLPAPER_CHANGED";
- public static final String PREVIEW_WALLPAPER_FILE_PATH = "preview_wallpaper.jpg";
- public static final String ROTATING_WALLPAPER_FILE_PATH = "rotating_wallpaper.jpg";
-
- private static final String TAG = "NoBackupImageWallpaper";
- private static final String GL_LOG_TAG = "ImageWallpaperGL";
- private static final boolean DEBUG = false;
- private static final boolean FIXED_SIZED_SURFACE = false;
-
- private final Handler mHandler = new Handler();
-
- private int mOpenGlContextCounter;
- private WallpaperManager mWallpaperManager;
- private DrawableEngine mEngine;
- private boolean mIsHardwareAccelerated;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mOpenGlContextCounter = 0;
- mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
-
- // By default, use OpenGL for drawing the static wallpaper image.
- mIsHardwareAccelerated = true;
- }
-
- @Override
- public void onTrimMemory(int level) {
- if (mEngine != null) {
- mEngine.trimMemory(level);
- }
- }
-
- @Override
- public Engine onCreateEngine() {
- mEngine = new DrawableEngine();
- return mEngine;
- }
-
- private class DrawableEngine extends Engine {
- static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- static final int EGL_OPENGL_ES2_BIT = 4;
- private static final String S_SIMPLE_VS =
- "attribute vec4 position;\n"
- + "attribute vec2 texCoords;\n"
- + "varying vec2 outTexCoords;\n"
- + "uniform mat4 projection;\n"
- + "\nvoid main(void) {\n"
- + " outTexCoords = texCoords;\n"
- + " gl_Position = projection * position;\n"
- + "}\n\n";
- private static final String S_SIMPLE_FS =
- "precision mediump float;\n\n"
- + "varying vec2 outTexCoords;\n"
- + "uniform sampler2D texture;\n"
- + "\nvoid main(void) {\n"
- + " gl_FragColor = texture2D(texture, outTexCoords);\n"
- + "}\n\n";
- private static final int FLOAT_SIZE_BYTES = 4;
- private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
- private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
- private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
- Bitmap mBackground;
- WallpaperColors mCachedWallpaperColors;
- int mBackgroundWidth = -1, mBackgroundHeight = -1;
- int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- int mLastRotation = -1;
- float mXOffset = 0.5f;
- float mYOffset = 0.5f;
- float mScale = 1f;
- boolean mVisible = true;
- boolean mOffsetsChanged;
- int mLastXTranslation;
- int mLastYTranslation;
- private Display mDefaultDisplay;
- private EGL10 mEgl;
- private EGLDisplay mEglDisplay;
- private EGLConfig mEglConfig;
- private EGLContext mEglContext;
- private EGLSurface mEglSurface;
- private int mTexture;
- private int mProgram;
- private boolean mIsOpenGlTextureLoaded;
- private int mRotationAtLastSurfaceSizeUpdate = -1;
- private int mDisplayWidthAtLastSurfaceSizeUpdate = -1;
- private int mDisplayHeightAtLastSurfaceSizeUpdate = -1;
-
- private int mLastRequestedWidth = -1;
- private int mLastRequestedHeight = -1;
- private AsyncTask<Void, Void, Bitmap> mLoader;
- private boolean mNeedsDrawAfterLoadingWallpaper;
- private boolean mSurfaceValid;
-
- private BroadcastReceiver mReceiver;
-
- public DrawableEngine() {
- super();
- }
-
- public void trimMemory(int level) {
- if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW
- && mBackground != null) {
- if (DEBUG) {
- Log.d(TAG, "trimMemory");
- }
- mBackground.recycle();
- mBackground = null;
- mBackgroundWidth = -1;
- mBackgroundHeight = -1;
- }
- }
-
- @Override
- public void onCreate(SurfaceHolder surfaceHolder) {
- if (DEBUG) {
- Log.d(TAG, "onCreate");
- }
-
- super.onCreate(surfaceHolder);
-
- mIsOpenGlTextureLoaded = false;
-
- mDefaultDisplay = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay();
-
- updateSurfaceSize(surfaceHolder, mDefaultDisplay, false /* forDraw */);
-
- // Enable offset notifications to pan wallpaper for parallax effect.
- setOffsetNotificationsEnabled(true);
-
- // If not a preview, then register a local broadcast receiver for listening to changes in the
- // rotating wallpaper file.
- if (!isPreview()) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(getPackageName() + ACTION_ROTATING_WALLPAPER_CHANGED);
-
- mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.i(TAG, "Broadcast received with intent: " + intent);
- }
-
- String action = intent.getAction();
- if (action.equals(getPackageName() + ACTION_ROTATING_WALLPAPER_CHANGED)) {
- DrawableEngine.this.invalidateAndRedrawWallpaper();
- }
- }
- };
-
- registerReceiver(mReceiver, filter, getPackageName()
- + PERMISSION_NOTIFY_ROTATING_WALLPAPER_CHANGED, null /* handler */);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mBackground = null;
- mWallpaperManager.forgetLoadedWallpaper();
-
- if (!isPreview() && mReceiver != null) {
- unregisterReceiver(mReceiver);
- }
- }
-
- boolean updateSurfaceSize(SurfaceHolder surfaceHolder, Display display, boolean forDraw) {
- boolean hasWallpaper = true;
- Point displaySize = ScreenSizeCalculator.getInstance().getScreenSize(display);
-
- // Load background image dimensions, if we haven't saved them yet
- if (mBackgroundWidth <= 0 || mBackgroundHeight <= 0) {
- // Need to load the image to get dimensions
- loadWallpaper(forDraw);
- if (DEBUG) {
- Log.d(TAG, "Reloading, redoing updateSurfaceSize later.");
- }
- hasWallpaper = false;
- }
-
- // Force the wallpaper to cover the screen in both dimensions
- int surfaceWidth = Math.max(displaySize.x, mBackgroundWidth);
- int surfaceHeight = Math.max(displaySize.y, mBackgroundHeight);
-
- if (FIXED_SIZED_SURFACE) {
- // Used a fixed size surface, because we are special. We can do
- // this because we know the current design of window animations doesn't
- // cause this to break.
- surfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
- mLastRequestedWidth = surfaceWidth;
- mLastRequestedHeight = surfaceHeight;
- } else {
- surfaceHolder.setSizeFromLayout();
- }
- return hasWallpaper;
- }
-
- @Override
- public void onVisibilityChanged(boolean visible) {
- if (DEBUG) {
- Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible);
- }
-
- if (mVisible != visible) {
- if (DEBUG) {
- Log.d(TAG, "Visibility changed to visible=" + visible);
- }
- mVisible = visible;
- drawFrame(false /* forceRedraw */);
- }
- }
-
- @Override
- public void onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
- }
-
- @Override
- public void onOffsetsChanged(float xOffset, float yOffset,
- float xOffsetStep, float yOffsetStep,
- int xPixels, int yPixels) {
- if (DEBUG) {
- Log.d(TAG, "onOffsetsChanged: xOffset=" + xOffset + ", yOffset=" + yOffset
- + ", xOffsetStep=" + xOffsetStep + ", yOffsetStep=" + yOffsetStep
- + ", xPixels=" + xPixels + ", yPixels=" + yPixels);
- }
-
- if (mXOffset != xOffset || mYOffset != yOffset) {
- if (DEBUG) {
- Log.d(TAG, "Offsets changed to (" + xOffset + "," + yOffset + ").");
- }
- mXOffset = xOffset;
- mYOffset = yOffset;
- mOffsetsChanged = true;
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- drawFrame(false /* forceRedraw */);
- }
- });
- }
-
- @Override
- public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- if (DEBUG) {
- Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height);
- }
-
- super.onSurfaceChanged(holder, format, width, height);
-
- // Retrieve buffer in new size.
- if (mEgl != null) {
- mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
- }
- drawFrame(false /* forceRedraw */);
- }
-
- @Override
- public void onSurfaceDestroyed(SurfaceHolder holder) {
- super.onSurfaceDestroyed(holder);
- if (DEBUG) {
- Log.d(TAG, "onSurfaceDestroyed");
- }
- mLastSurfaceWidth = mLastSurfaceHeight = -1;
- mSurfaceValid = false;
-
- if (mIsHardwareAccelerated) {
- finishGL(mTexture, mProgram);
- }
- }
-
- @Override
- public void onSurfaceCreated(SurfaceHolder holder) {
- super.onSurfaceCreated(holder);
- if (DEBUG) {
- Log.d(TAG, "onSurfaceCreated");
- }
- mLastSurfaceWidth = mLastSurfaceHeight = -1;
- mSurfaceValid = true;
-
- if (mIsHardwareAccelerated) {
- if (!initGL(holder)) {
- // Fall back to canvas drawing if initializing OpenGL failed.
- mIsHardwareAccelerated = false;
- mEgl = null;
- }
- }
- }
-
- @Override
- public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
- if (DEBUG) {
- Log.d(TAG, "onSurfaceRedrawNeeded");
- }
- super.onSurfaceRedrawNeeded(holder);
-
- drawFrame(true /* forceRedraw */);
- }
-
- @RequiresApi(VERSION_CODES.O_MR1)
- @Override
- public WallpaperColors onComputeColors() {
- // It's OK to return null here.
- return mCachedWallpaperColors;
- }
-
- /**
- * Invalidates the currently-drawn wallpaper image, causing the engine to reload the image from
- * disk and draw the new wallpaper image.
- */
- public void invalidateAndRedrawWallpaper() {
- // If a wallpaper load was already in flight, cancel it and restart a load in order to decode
- // the new image.
- if (mLoader != null) {
- mLoader.cancel(true /* mayInterruptIfRunning */);
- mLoader = null;
- }
-
- loadWallpaper(true /* needsDraw */);
- }
-
- void drawFrame(boolean forceRedraw) {
- if (!mSurfaceValid) {
- return;
- }
-
- Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(mDefaultDisplay);
- int newRotation = mDefaultDisplay.getRotation();
-
- // Sometimes a wallpaper is not large enough to cover the screen in one dimension.
- // Call updateSurfaceSize -- it will only actually do the update if the dimensions
- // should change
- if (newRotation != mLastRotation) {
- // Update surface size (if necessary)
- if (!updateSurfaceSize(getSurfaceHolder(), mDefaultDisplay, true /* forDraw */)) {
- return;
- }
- mRotationAtLastSurfaceSizeUpdate = newRotation;
- mDisplayWidthAtLastSurfaceSizeUpdate = screenSize.x;
- mDisplayHeightAtLastSurfaceSizeUpdate = screenSize.y;
- }
- SurfaceHolder sh = getSurfaceHolder();
- final Rect frame = sh.getSurfaceFrame();
- final int dw = frame.width();
- final int dh = frame.height();
- boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth
- || dh != mLastSurfaceHeight;
-
- boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation
- || forceRedraw;
- if (!redrawNeeded && !mOffsetsChanged) {
- if (DEBUG) {
- Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
- + "and offsets have not changed.");
- }
- return;
- }
- mLastRotation = newRotation;
-
- // Load bitmap if its null and we're not using hardware acceleration.
- if ((mIsHardwareAccelerated && !mIsOpenGlTextureLoaded) // Using OpenGL but texture not loaded
- || (!mIsHardwareAccelerated && mBackground == null)) { // Draw with Canvas but no bitmap
- if (DEBUG) {
- Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = "
- + mBackground + ", " + ((mBackground == null) ? 0 : mBackground.getWidth()) + ", "
- + ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " + dw + ", " + dh);
- }
- loadWallpaper(true /* needDraw */);
- if (DEBUG) {
- Log.d(TAG, "Reloading, resuming draw later");
- }
- return;
- }
-
- // Center the scaled image
- mScale = Math.max(1f, Math.max(dw / (float) mBackgroundWidth,
- dh / (float) mBackgroundHeight));
- final int availw = dw - (int) (mBackgroundWidth * mScale);
- final int availh = dh - (int) (mBackgroundHeight * mScale);
- int xPixels = availw / 2;
- int yPixels = availh / 2;
-
- // Adjust the image for xOffset/yOffset values. If window manager is handling offsets,
- // mXOffset and mYOffset are set to 0.5f by default and therefore xPixels and yPixels
- // will remain unchanged
- final int availwUnscaled = dw - mBackgroundWidth;
- final int availhUnscaled = dh - mBackgroundHeight;
- if (availwUnscaled < 0) {
- xPixels += (int) (availwUnscaled * (mXOffset - .5f) + .5f);
- }
- if (availhUnscaled < 0) {
- yPixels += (int) (availhUnscaled * (mYOffset - .5f) + .5f);
- }
-
- mOffsetsChanged = false;
- if (surfaceDimensionsChanged) {
- mLastSurfaceWidth = dw;
- mLastSurfaceHeight = dh;
- }
- if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
- if (DEBUG) {
- Log.d(TAG, "Suppressed drawFrame since the image has not "
- + "actually moved an integral number of pixels.");
- }
- return;
- }
- mLastXTranslation = xPixels;
- mLastYTranslation = yPixels;
-
- if (DEBUG) {
- Log.d(TAG, "Redrawing wallpaper");
- }
-
- if (mIsHardwareAccelerated) {
- if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
- drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
- } else {
- // If OpenGL drawing was successful, then we can safely discard a reference to the
- // wallpaper bitmap to save memory (since a copy has already been loaded into an OpenGL
- // texture).
- mBackground = null;
- }
- } else {
- drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
- }
- }
-
- /**
- * Loads the wallpaper on background thread and schedules updating the surface frame,
- * and if {@param needsDraw} is set also draws a frame.
- * <p>
- * If loading is already in-flight, subsequent loads are ignored (but needDraw is or-ed to
- * the active request).
- * <p>
- * If {@param needsReset} is set also clears the cache in WallpaperManager first.
- */
- private void loadWallpaper(boolean needsDraw) {
- mNeedsDrawAfterLoadingWallpaper |= needsDraw;
- if (mLoader != null) {
- if (DEBUG) {
- Log.d(TAG, "Skipping loadWallpaper, already in flight ");
- }
- return;
- }
- mLoader = new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- Throwable exception = null;
- try {
- // Decode bitmap of rotating image wallpaper.
- String wallpaperFilePath = isPreview()
- ? PREVIEW_WALLPAPER_FILE_PATH : ROTATING_WALLPAPER_FILE_PATH;
- Context context = isPreview() ? getApplicationContext()
- : getApplicationContext().createDeviceProtectedStorageContext();
- FileInputStream fileInputStream = context.openFileInput(wallpaperFilePath);
- Bitmap bitmap = BitmapFactory.decodeStream(fileInputStream);
- fileInputStream.close();
- return bitmap;
- } catch (RuntimeException | FileNotFoundException | OutOfMemoryError e) {
- Log.i(TAG, "couldn't decode stream: ", e);
- exception = e;
- } catch (IOException e) {
- Log.i(TAG, "couldn't close stream: ", e);
- exception = e;
- }
-
- if (isCancelled()) {
- return null;
- }
-
- if (exception != null) {
- // Note that if we do fail at this, and the default wallpaper can't
- // be loaded, we will go into a cycle. Don't do a build where the
- // default wallpaper can't be loaded.
- Log.w(TAG, "Unable to load wallpaper!", exception);
- try {
- return ((BitmapDrawable) getFallbackDrawable()).getBitmap();
- } catch (OutOfMemoryError ex) {
- // now we're really screwed.
- Log.w(TAG, "Unable reset to default wallpaper!", ex);
- }
-
- if (isCancelled()) {
- return null;
- }
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Bitmap b) {
- mBackground = null;
- mBackgroundWidth = -1;
- mBackgroundHeight = -1;
-
- if (b != null) {
- mBackground = b;
- mBackgroundWidth = mBackground.getWidth();
- mBackgroundHeight = mBackground.getHeight();
-
- if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
- mCachedWallpaperColors = WallpaperColors.fromBitmap(mBackground);
- notifyColorsChanged();
- }
- }
-
- if (DEBUG) {
- Log.d(TAG, "Wallpaper loaded: " + mBackground);
- }
- updateSurfaceSize(getSurfaceHolder(), mDefaultDisplay,
- false /* forDraw */);
- if (mTexture != 0 && mEgl != null) {
- deleteTexture(mTexture);
- }
- // If background is absent (due to an error decoding the bitmap) then don't try to load
- // a texture.
- if (mEgl != null && mBackground != null) {
- mTexture = loadTexture(mBackground);
- }
- if (mNeedsDrawAfterLoadingWallpaper) {
- drawFrame(true /* forceRedraw */);
- }
-
- mLoader = null;
- mNeedsDrawAfterLoadingWallpaper = false;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- private Drawable getFallbackDrawable() {
- Drawable drawable;
- try {
- drawable = mWallpaperManager.getDrawable();
- } catch (java.lang.Exception e) {
- // Work around Samsung bug where SecurityException is thrown if device is still using its
- // default wallpaper, and around Android 7.0 bug where SELinux issues can cause a perfectly
- // valid access of the current wallpaper to cause a failed Binder transaction manifest here
- // as a RuntimeException.
- drawable = mWallpaperManager.getBuiltInDrawable();
- }
- return drawable;
- }
-
- @Override
- protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
- super.dump(prefix, fd, out, args);
-
- out.print(prefix);
- out.println("ImageWallpaper.DrawableEngine:");
- out.print(prefix);
- out.print(" mBackground=");
- out.print(mBackground);
- out.print(" mBackgroundWidth=");
- out.print(mBackgroundWidth);
- out.print(" mBackgroundHeight=");
- out.println(mBackgroundHeight);
-
- out.print(prefix);
- out.print(" mLastRotation=");
- out.print(mLastRotation);
- out.print(" mLastSurfaceWidth=");
- out.print(mLastSurfaceWidth);
- out.print(" mLastSurfaceHeight=");
- out.println(mLastSurfaceHeight);
-
- out.print(prefix);
- out.print(" mXOffset=");
- out.print(mXOffset);
- out.print(" mYOffset=");
- out.println(mYOffset);
-
- out.print(prefix);
- out.print(" mVisible=");
- out.print(mVisible);
- out.print(" mOffsetsChanged=");
- out.println(mOffsetsChanged);
-
- out.print(prefix);
- out.print(" mLastXTranslation=");
- out.print(mLastXTranslation);
- out.print(" mLastYTranslation=");
- out.print(mLastYTranslation);
- out.print(" mScale=");
- out.println(mScale);
-
- out.print(prefix);
- out.print(" mLastRequestedWidth=");
- out.print(mLastRequestedWidth);
- out.print(" mLastRequestedHeight=");
- out.println(mLastRequestedHeight);
-
- out.print(prefix);
- out.println(" DisplayInfo at last updateSurfaceSize:");
- out.print(prefix);
- out.print(" rotation=");
- out.print(mRotationAtLastSurfaceSizeUpdate);
- out.print(" width=");
- out.print(mDisplayWidthAtLastSurfaceSizeUpdate);
- out.print(" height=");
- out.println(mDisplayHeightAtLastSurfaceSizeUpdate);
- }
-
- private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int left, int top) {
- Canvas c = sh.lockCanvas();
- if (c != null) {
- try {
- if (DEBUG) {
- Log.d(TAG, "Redrawing: left=" + left + ", top=" + top);
- }
-
- final float right = left + mBackgroundWidth * mScale;
- final float bottom = top + mBackgroundHeight * mScale;
- if (w < 0 || h < 0) {
- c.save();
- c.clipOutRect(left, top, right, bottom);
- c.drawColor(0xff000000);
- c.restore();
- }
- if (mBackground != null) {
- RectF dest = new RectF(left, top, right, bottom);
- // add a filter bitmap?
- c.drawBitmap(mBackground, null, dest, null);
- }
- } finally {
- sh.unlockCanvasAndPost(c);
- }
- }
- }
-
- private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
-
- mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
-
- final float right = left + mBackgroundWidth * mScale;
- final float bottom = top + mBackgroundHeight * mScale;
-
- final Rect frame = sh.getSurfaceFrame();
- final Matrix4f ortho = new Matrix4f();
- ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
-
- final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
-
- final int attribPosition = GLES20.glGetAttribLocation(mProgram, "position");
- final int attribTexCoords = GLES20.glGetAttribLocation(mProgram, "texCoords");
- final int uniformTexture = GLES20.glGetUniformLocation(mProgram, "texture");
- final int uniformProjection = GLES20.glGetUniformLocation(mProgram, "projection");
-
- checkGlError();
-
- GLES20.glViewport(0, 0, frame.width(), frame.height());
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture);
-
- GLES20.glUseProgram(mProgram);
- GLES20.glEnableVertexAttribArray(attribPosition);
- GLES20.glEnableVertexAttribArray(attribTexCoords);
- GLES20.glUniform1i(uniformTexture, 0);
- GLES20.glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
-
- checkGlError();
-
- if (w > 0 || h > 0) {
- GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- }
-
- // drawQuad
- triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
- GLES20.glVertexAttribPointer(attribPosition, 3, GLES20.GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
- triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
- GLES20.glVertexAttribPointer(attribTexCoords, 3, GLES20.GL_FLOAT, false,
- TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
-
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
-
- boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
- checkEglError();
-
- return status;
- }
-
- private FloatBuffer createMesh(int left, int top, float right, float bottom) {
- final float[] verticesData = {
- // X, Y, Z, U, V
- left, bottom, 0.0f, 0.0f, 1.0f,
- right, bottom, 0.0f, 1.0f, 1.0f,
- left, top, 0.0f, 0.0f, 0.0f,
- right, top, 0.0f, 1.0f, 0.0f,
- };
-
- final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
- final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
- ByteOrder.nativeOrder()).asFloatBuffer();
- triangleVertices.put(verticesData).position(0);
- return triangleVertices;
- }
-
- private int loadTexture(Bitmap bitmap) {
- mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
-
- int[] textures = new int[1];
-
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glGenTextures(1, textures, 0);
- checkGlError();
-
- int texture = textures[0];
- GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
- checkGlError();
-
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
-
- GLES20.glTexParameteri(
- GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(
- GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
-
- GLUtils.texImage2D(
- GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap, GLES20.GL_UNSIGNED_BYTE, 0);
- checkGlError();
-
- mIsOpenGlTextureLoaded = true;
-
- return texture;
- }
-
- private int buildProgram(String vertex, String fragment) {
- int vertexShader = buildShader(vertex, GLES20.GL_VERTEX_SHADER);
- if (vertexShader == 0) {
- return 0;
- }
-
- int fragmentShader = buildShader(fragment, GLES20.GL_FRAGMENT_SHADER);
- if (fragmentShader == 0) {
- return 0;
- }
-
- int program = GLES20.glCreateProgram();
- GLES20.glAttachShader(program, vertexShader);
- GLES20.glAttachShader(program, fragmentShader);
- GLES20.glLinkProgram(program);
- checkGlError();
-
- GLES20.glDeleteShader(vertexShader);
- GLES20.glDeleteShader(fragmentShader);
-
- int[] status = new int[1];
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
- if (status[0] != GLES20.GL_TRUE) {
- String error = GLES20.glGetProgramInfoLog(program);
- Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
- GLES20.glDeleteProgram(program);
- return 0;
- }
-
- return program;
- }
-
- private int buildShader(String source, int type) {
- int shader = GLES20.glCreateShader(type);
-
- GLES20.glShaderSource(shader, source);
- checkGlError();
-
- GLES20.glCompileShader(shader);
- checkGlError();
-
- int[] status = new int[1];
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, status, 0);
- if (status[0] != GLES20.GL_TRUE) {
- String error = GLES20.glGetShaderInfoLog(shader);
- Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
- GLES20.glDeleteShader(shader);
- return 0;
- }
-
- return shader;
- }
-
- private void checkEglError() {
- int error = mEgl.eglGetError();
- if (error != EGL10.EGL_SUCCESS) {
- Log.w(GL_LOG_TAG, "EGL error = " + GLUtils.getEGLErrorString(error));
- }
- }
-
- private void checkGlError() {
- int error = GLES20.glGetError();
- if (error != GLES20.GL_NO_ERROR) {
- Log.w(GL_LOG_TAG, "GL error = 0x" + Integer.toHexString(error), new Throwable());
- }
- }
-
- private void deleteTexture(int texture) {
- int[] textures = new int[1];
- textures[0] = texture;
-
- mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
- GLES20.glDeleteTextures(1, textures, 0);
- mTexture = 0;
- }
-
- private void finishGL(int texture, int program) {
- if (mEgl == null) {
- return;
- }
-
- mOpenGlContextCounter--;
-
- mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
- deleteTexture(mTexture);
- GLES20.glDeleteProgram(program);
- mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- if (mOpenGlContextCounter == 0) {
- mEgl.eglTerminate(mEglDisplay);
- }
-
- mEgl = null;
- }
-
- private boolean initGL(SurfaceHolder surfaceHolder) {
- mEgl = (EGL10) EGLContext.getEGL();
-
- mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
- if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
- throw new RuntimeException("eglGetDisplay failed "
- + GLUtils.getEGLErrorString(mEgl.eglGetError()));
- }
-
- int[] version = new int[2];
- if (!mEgl.eglInitialize(mEglDisplay, version)) {
- throw new RuntimeException("eglInitialize failed "
- + GLUtils.getEGLErrorString(mEgl.eglGetError()));
- }
-
- mOpenGlContextCounter++;
-
- mEglConfig = chooseEglConfig();
- if (mEglConfig == null) {
- throw new RuntimeException("eglConfig not initialized");
- }
-
- mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
- if (mEglContext == EGL_NO_CONTEXT) {
- throw new RuntimeException("createContext failed "
- + GLUtils.getEGLErrorString(mEgl.eglGetError()));
- }
-
- int attribs[] = {
- EGL10.EGL_WIDTH, 1,
- EGL10.EGL_HEIGHT, 1,
- EGL10.EGL_NONE
- };
- EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
- mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
-
- int[] maxSize = new int[1];
- Rect frame = surfaceHolder.getSurfaceFrame();
- GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);
-
- mEgl.eglMakeCurrent(
- mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
-
- if (frame.width() > maxSize[0] || frame.height() > maxSize[0]) {
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- mEgl.eglTerminate(mEglDisplay);
- Log.e(GL_LOG_TAG, "requested texture size " + frame.width() + "x" + frame.height()
- + " exceeds the support maximum of " + maxSize[0] + "x" + maxSize[0]);
- return false;
- }
-
- mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
- if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
- int error = mEgl.eglGetError();
- if (error == EGL10.EGL_BAD_NATIVE_WINDOW || error == EGL10.EGL_BAD_ALLOC) {
- Log.e(GL_LOG_TAG, "createWindowSurface returned " + GLUtils.getEGLErrorString(error)
- + ".");
- return false;
- }
- throw new RuntimeException("createWindowSurface failed "
- + GLUtils.getEGLErrorString(error));
- }
-
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- throw new RuntimeException("eglMakeCurrent failed "
- + GLUtils.getEGLErrorString(mEgl.eglGetError()));
- }
-
- mProgram = buildProgram(S_SIMPLE_VS, S_SIMPLE_FS);
- if (mBackground != null) {
- mTexture = loadTexture(mBackground);
- }
-
- return true;
- }
-
-
- EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
- int[] attribList = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
- return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attribList);
- }
-
- private EGLConfig chooseEglConfig() {
- int[] configsCount = new int[1];
- EGLConfig[] configs = new EGLConfig[1];
- int[] configSpec = getConfig();
- if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
- throw new IllegalArgumentException("eglChooseConfig failed "
- + GLUtils.getEGLErrorString(mEgl.eglGetError()));
- } else if (configsCount[0] > 0) {
- return configs[0];
- }
- return null;
- }
-
- private int[] getConfig() {
- return new int[]{
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL10.EGL_RED_SIZE, 8,
- EGL10.EGL_GREEN_SIZE, 8,
- EGL10.EGL_BLUE_SIZE, 8,
- EGL10.EGL_ALPHA_SIZE, 0,
- EGL10.EGL_DEPTH_SIZE, 0,
- EGL10.EGL_STENCIL_SIZE, 0,
- EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_NONE,
- EGL10.EGL_NONE
- };
- }
- }
-}
diff --git a/src/com/android/wallpaper/module/RotatingWallpaperComponentChecker.java b/src/com/android/wallpaper/module/RotatingWallpaperComponentChecker.java
deleted file mode 100755
index 8a2908a..0000000
--- a/src/com/android/wallpaper/module/RotatingWallpaperComponentChecker.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.wallpaper.module;
-
-import android.content.Context;
-
-import androidx.annotation.IntDef;
-
-/**
- * Checks what component is responsible for presenting the rotating wallpaper image under the
- * device's launcher or keyguard for current and future rotations.
- */
-public interface RotatingWallpaperComponentChecker {
-
- int ROTATING_WALLPAPER_COMPONENT_LIVE = 1;
- int ROTATING_WALLPAPER_COMPONENT_STATIC = 2;
-
- int ROTATING_WALLPAPER_SUPPORT_NOT_SUPPORTED = 0;
- int ROTATING_WALLPAPER_SUPPORT_SUPPORTED = 1;
-
- /**
- * Returns the rotating wallpaper component for the current wallpaper rotation.
- */
- @RotatingWallpaperComponent
- int getCurrentRotatingWallpaperComponent(Context context);
-
- /**
- * Returns the rotating wallpaper component for future wallpaper rotations.
- */
- @RotatingWallpaperComponent
- int getNextRotatingWallpaperComponent(Context context);
-
- /**
- * Returns the support level for rotating wallpaper.
- */
- @RotatingWallpaperSupport
- int getRotatingWallpaperSupport(Context context);
-
- /**
- * Possible components for presenting the rotating wallpaper image.
- */
- @IntDef({
- ROTATING_WALLPAPER_COMPONENT_LIVE,
- ROTATING_WALLPAPER_COMPONENT_STATIC})
- @interface RotatingWallpaperComponent {
- }
-
- /**
- * Possible support levels for rotating wallpaper.
- */
- @IntDef({
- ROTATING_WALLPAPER_SUPPORT_NOT_SUPPORTED,
- ROTATING_WALLPAPER_SUPPORT_SUPPORTED})
- @interface RotatingWallpaperSupport {
- }
-}
diff --git a/src/com/android/wallpaper/module/RotationWallpaperMoveReceiver.java b/src/com/android/wallpaper/module/RotationWallpaperMoveReceiver.java
deleted file mode 100644
index 975b0db..0000000
--- a/src/com/android/wallpaper/module/RotationWallpaperMoveReceiver.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.android.wallpaper.module;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-import com.android.wallpaper.compat.BuildCompat;
-import com.android.wallpaper.util.DiskBasedLogger;
-import com.android.wallpaper.util.FileMover;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Receiver to run when the app was updated or on first boot to migrate previously existing rotating
- * wallpaper file to device protected storage so it can be read in direct-boot.
- * This is basically a no-op if there's no file in
- * {@link NoBackupImageWallpaper#ROTATING_WALLPAPER_FILE_PATH}.
- */
-public class RotationWallpaperMoveReceiver extends BroadcastReceiver {
-
- private static final String TAG = "RotationWallpaperMoveReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- // This receiver is a no-op on pre-N Android and should only respond to a
- // MY_PACKAGE_REPLACED intent.
- if (intent.getAction() == null
- || !(intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)
- || intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
- || !BuildCompat.isAtLeastN()) {
- DiskBasedLogger.e(
- TAG,
- "Unexpected action or Android version!",
- context);
- throw new IllegalStateException(
- "Unexpected broadcast action or unsupported Android version");
- }
-
- // This is a no-op if there is no rotating wallpaper file in the files directory.
- if (!context.getFileStreamPath(
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH).exists()) {
- return;
- }
-
- PendingResult broadcastResult = goAsync();
- new Thread(() -> {
- Context appContext = context.getApplicationContext();
- Context deviceProtectedContext = appContext.createDeviceProtectedStorageContext();
- try {
- File movedFile = FileMover.moveFileBetweenContexts(appContext,
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH,
- deviceProtectedContext,
- NoBackupImageWallpaper.ROTATING_WALLPAPER_FILE_PATH);
-
- if (movedFile != null) {
- // Notify NoBackupImageWallpaper of the change in case that's the currently
- // set wallpaper
- Intent intent1 = new Intent(appContext.getPackageName()
- + NoBackupImageWallpaper.ACTION_ROTATING_WALLPAPER_CHANGED);
- // Handled by a runtime-registered receiver in NoBackupImageWallpaper.
- intent1.setPackage(appContext.getPackageName());
- appContext.sendBroadcast(intent1);
- }
- } catch (IOException e) {
- DiskBasedLogger.e(
- TAG,
- "Failed to move rotating wallpaper file to device protected storage: "
- + e.getMessage(),
- appContext);
- } finally {
- broadcastResult.finish();
- }
- }).start();
-
- }
-}
diff --git a/src/com/android/wallpaper/module/RotationWallpaperUpdateReceiver.java b/src/com/android/wallpaper/module/RotationWallpaperUpdateReceiver.java
new file mode 100644
index 0000000..4fbc20d
--- /dev/null
+++ b/src/com/android/wallpaper/module/RotationWallpaperUpdateReceiver.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.module;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.android.wallpaper.compat.BuildCompat;
+import com.android.wallpaper.util.DiskBasedLogger;
+import com.android.wallpaper.util.FileMover;
+
+import java.io.File;
+
+/**
+ * Receiver to run when the app was updated or on first boot to switch from live rotating wallpaper
+ * to static rotating wallpaper.
+ */
+public class RotationWallpaperUpdateReceiver extends BroadcastReceiver {
+
+
+ // Earlier versions of rotating wallpaper save the current rotation image as a file.
+ // We can infer from the extistance of this file whether or not user had rotating live wallpaper
+ private static final String ROTATING_WALLPAPER_FILE_PATH = "rotating_wallpaper.jpg";
+ private static final String TAG = "RotationWallpaperUpdateReceiver";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // This receiver is a no-op on pre-N Android and should only respond to a
+ // MY_PACKAGE_REPLACED intent.
+ if (intent.getAction() == null
+ || !(intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)
+ || intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
+ || !BuildCompat.isAtLeastN()) {
+ DiskBasedLogger.e(
+ TAG,
+ "Unexpected action or Android version!",
+ context);
+ throw new IllegalStateException(
+ "Unexpected broadcast action or unsupported Android version");
+ }
+
+ PendingResult broadcastResult = goAsync();
+ new Thread(() -> {
+ Context appContext = context.getApplicationContext();
+ Context deviceProtectedContext = appContext.createDeviceProtectedStorageContext();
+
+ if (context.getFileStreamPath(ROTATING_WALLPAPER_FILE_PATH).exists()) {
+ moveFileToProtectedStorage(appContext, deviceProtectedContext);
+ }
+
+ File wallpaperFile = deviceProtectedContext.getFileStreamPath(
+ ROTATING_WALLPAPER_FILE_PATH);
+ if (wallpaperFile.exists()) {
+ switchToStaticWallpaper(appContext, wallpaperFile);
+ }
+ broadcastResult.finish();
+ }).start();
+ }
+
+ private void moveFileToProtectedStorage(Context context, Context deviceProtectedContext) {
+ try {
+ FileMover.moveFileBetweenContexts(context, ROTATING_WALLPAPER_FILE_PATH,
+ deviceProtectedContext, ROTATING_WALLPAPER_FILE_PATH);
+ } catch (Exception ex) {
+ DiskBasedLogger.e(
+ TAG,
+ "Failed to move rotating wallpaper file to device protected storage: "
+ + ex.getMessage(),
+ context);
+ }
+ }
+
+ private void switchToStaticWallpaper(Context appContext, File wallpaperFile) {
+ try {
+ Injector injector = InjectorProvider.getInjector();
+ WallpaperPreferences wallpaperPreferences = injector.getPreferences(appContext);
+ if (wallpaperPreferences.getWallpaperPresentationMode()
+ != WallpaperPreferences.PRESENTATION_MODE_ROTATING) {
+ return;
+ }
+ Bitmap bitmap = BitmapFactory.decodeFile(wallpaperFile.getAbsolutePath());
+
+ injector.getWallpaperPersister(appContext).setWallpaperInRotation(bitmap,
+ wallpaperPreferences.getHomeWallpaperAttributions(),
+ wallpaperPreferences.getHomeWallpaperActionLabelRes(),
+ wallpaperPreferences.getHomeWallpaperActionIconRes(),
+ wallpaperPreferences.getHomeWallpaperActionUrl(),
+ wallpaperPreferences.getHomeWallpaperCollectionId());
+ wallpaperFile.delete();
+
+ } catch (Exception ex) {
+ DiskBasedLogger.e(TAG, "Unable to set static wallpaper", appContext);
+ }
+ }
+}
diff --git a/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java b/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java
index f63506f..e4c6588 100755
--- a/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java
+++ b/src/com/android/wallpaper/module/WallpaperPreferenceKeys.java
@@ -28,12 +28,7 @@ public class WallpaperPreferenceKeys {
public static final String KEY_HOME_WALLPAPER_ACTION_LABEL_RES = "home_wallpaper_action_label";
public static final String KEY_HOME_WALLPAPER_ACTION_ICON_RES = "home_wallpaper_action_icon";
public static final String KEY_HOME_WALLPAPER_COLLECTION_ID = "home_wallpaper_collection_id";
- public static final String KEY_HOME_WALLPAPER_BASE_IMAGE_URL = "home_wallpaper_base_image_url";
public static final String KEY_HOME_WALLPAPER_HASH_CODE = "home_wallpaper_hash_code";
- public static final String KEY_HOME_WALLPAPER_MANAGER_ID = "home_wallpaper_id";
- public static final String KEY_HOME_WALLPAPER_PACKAGE_NAME = "home_wallpaper_package_name";
- public static final String KEY_HOME_WALLPAPER_REMOTE_ID = "home_wallpaper_remote_id";
- public static final String KEY_HOME_WALLPAPER_BACKING_FILE = "home_wallpaper_backing_file";
public static final String KEY_LOCK_WALLPAPER_ATTRIB_1 = "lock_wallpaper_attribution_line_1";
public static final String KEY_LOCK_WALLPAPER_ATTRIB_2 = "lock_wallpaper_attribution_line_2";
@@ -43,24 +38,35 @@ public class WallpaperPreferenceKeys {
public static final String KEY_LOCK_WALLPAPER_ACTION_ICON_RES = "lock_wallpaper_action_icon";
public static final String KEY_LOCK_WALLPAPER_HASH_CODE = "lock_wallpaper_hash_code";
public static final String KEY_LOCK_WALLPAPER_COLLECTION_ID = "lock_wallpaper_collection_id";
- public static final String KEY_LOCK_WALLPAPER_MANAGER_ID = "lock_wallpaper_id";
- public static final String KEY_LOCK_WALLPAPER_BACKING_FILE = "lock_wallpaper_backing_file";
- public static final String KEY_DAILY_ROTATION_TIMESTAMPS = "daily_rotation_timestamps";
- public static final String KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP =
- "daily_wallpaper_enabled_timestamp";
-
- public static final String KEY_LAST_DAILY_LOG_TIMESTAMP = "last_daily_log_timestamp";
- public static final String KEY_LAST_APP_ACTIVE_TIMESTAMP = "last_app_active_timestamp";
- public static final String KEY_LAST_ROTATION_STATUS = "last_rotation_status";
- public static final String KEY_LAST_ROTATION_STATUS_TIMESTAMP = "last_rotation_status_timestamp";
- public static final String KEY_LAST_SYNC_TIMESTAMP = "last_sync_timestamp";
-
- public static final String KEY_PENDING_WALLPAPER_SET_STATUS = "pending_wallpaper_set_status";
- public static final String KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS =
- "pending_daily_wallpaper_update_status";
-
- public static final String KEY_NUM_DAYS_DAILY_ROTATION_FAILED = "num_days_daily_rotation_failed";
- public static final String KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED =
- "num_days_daily_rotation_not_attempted";
+ /**
+ * Preferences with these keys should not be backed up
+ */
+ public interface NoBackupKeys {
+ public static final String KEY_HOME_WALLPAPER_BASE_IMAGE_URL =
+ "home_wallpaper_base_image_url";
+ public static final String KEY_HOME_WALLPAPER_MANAGER_ID = "home_wallpaper_id";
+ public static final String KEY_HOME_WALLPAPER_REMOTE_ID = "home_wallpaper_remote_id";
+ public static final String KEY_HOME_WALLPAPER_BACKING_FILE = "home_wallpaper_backing_file";
+ public static final String KEY_LOCK_WALLPAPER_MANAGER_ID = "lock_wallpaper_id";
+ public static final String KEY_LOCK_WALLPAPER_BACKING_FILE = "lock_wallpaper_backing_file";
+ public static final String KEY_DAILY_ROTATION_TIMESTAMPS = "daily_rotation_timestamps";
+ public static final String KEY_DAILY_WALLPAPER_ENABLED_TIMESTAMP =
+ "daily_wallpaper_enabled_timestamp";
+ public static final String KEY_LAST_DAILY_LOG_TIMESTAMP = "last_daily_log_timestamp";
+ public static final String KEY_LAST_APP_ACTIVE_TIMESTAMP = "last_app_active_timestamp";
+ public static final String KEY_LAST_ROTATION_STATUS = "last_rotation_status";
+ public static final String KEY_LAST_ROTATION_STATUS_TIMESTAMP =
+ "last_rotation_status_timestamp";
+ public static final String KEY_LAST_SYNC_TIMESTAMP = "last_sync_timestamp";
+ public static final String KEY_PENDING_WALLPAPER_SET_STATUS =
+ "pending_wallpaper_set_status";
+ public static final String KEY_PENDING_DAILY_WALLPAPER_UPDATE_STATUS =
+ "pending_daily_wallpaper_update_status";
+ public static final String KEY_NUM_DAYS_DAILY_ROTATION_FAILED =
+ "num_days_daily_rotation_failed";
+ public static final String KEY_NUM_DAYS_DAILY_ROTATION_NOT_ATTEMPTED =
+ "num_days_daily_rotation_not_attempted";
+ public static final String KEY_HOME_WALLPAPER_PACKAGE_NAME = "home_wallpaper_package_name";
+ }
}
diff --git a/src/com/android/wallpaper/module/WallpaperSetter.java b/src/com/android/wallpaper/module/WallpaperSetter.java
index 830d914..a33a5f1 100644
--- a/src/com/android/wallpaper/module/WallpaperSetter.java
+++ b/src/com/android/wallpaper/module/WallpaperSetter.java
@@ -72,8 +72,9 @@ public class WallpaperSetter {
* @param callback optional callback to be notified when the wallpaper is set.
*/
public void setCurrentWallpaper(Activity containerActivity, WallpaperInfo wallpaper,
- Asset wallpaperAsset, @Destination final int destination, float wallpaperScale,
- @Nullable Rect cropRect, @Nullable SetWallpaperCallback callback) {
+ @Nullable Asset wallpaperAsset, @Destination final int destination,
+ float wallpaperScale, @Nullable Rect cropRect,
+ @Nullable SetWallpaperCallback callback) {
if (wallpaper instanceof LiveWallpaperInfo) {
setCurrentLiveWallpaper(containerActivity, (LiveWallpaperInfo) wallpaper, destination,
callback);
diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
new file mode 100755
index 0000000..87e29c5
--- /dev/null
+++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2019 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 static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.ContextThemeWrapper;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.asset.Asset;
+import com.android.wallpaper.module.WallpaperPersister.Destination;
+import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
+import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.WallpaperCropUtils;
+import com.android.wallpaper.widget.MaterialProgressDrawable;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.MemoryCategory;
+import com.davemorrissey.labs.subscaleview.ImageSource;
+import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+
+import java.util.List;
+
+/**
+ * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
+ * information.
+ */
+public class ImagePreviewFragment extends PreviewFragment {
+
+ private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
+
+ private SubsamplingScaleImageView mFullResImageView;
+ private Asset mWallpaperAsset;
+ private TextView mAttributionTitle;
+ private TextView mAttributionSubtitle1;
+ private TextView mAttributionSubtitle2;
+ private Button mExploreButton;
+ private Button mSetWallpaperButton;
+
+ private Point mDefaultCropSurfaceSize;
+ private Point mScreenSize;
+ private Point mRawWallpaperSize; // Native size of wallpaper image.
+ private ImageView mLoadingIndicator;
+ private MaterialProgressDrawable mProgressDrawable;
+ private ImageView mLowResImageView;
+ private View mSpacer;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mWallpaperAsset = mWallpaper.getAsset(requireContext().getApplicationContext());
+ }
+
+ @Override
+ protected int getLayoutResId() {
+ return R.layout.fragment_image_preview;
+ }
+
+ @Override
+ protected int getBottomSheetResId() {
+ return R.id.bottom_sheet;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+
+ Activity activity = requireActivity();
+ // Set toolbar as the action bar.
+
+ mFullResImageView = view.findViewById(R.id.full_res_image);
+ mLoadingIndicator = view.findViewById(R.id.loading_indicator);
+
+ mAttributionTitle = view.findViewById(R.id.preview_attribution_pane_title);
+ mAttributionSubtitle1 = view.findViewById(R.id.preview_attribution_pane_subtitle1);
+ mAttributionSubtitle2 = view.findViewById(R.id.preview_attribution_pane_subtitle2);
+ mExploreButton = view.findViewById(R.id.preview_attribution_pane_explore_button);
+ mSetWallpaperButton = view.findViewById(R.id.preview_attribution_pane_set_wallpaper_button);
+
+ mLowResImageView = view.findViewById(R.id.low_res_image);
+ mSpacer = view.findViewById(R.id.spacer);
+
+ // Trim some memory from Glide to make room for the full-size image in this fragment.
+ Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
+
+ mDefaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
+ getResources(), activity.getWindowManager().getDefaultDisplay());
+ mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+ activity.getWindowManager().getDefaultDisplay());
+
+ // Load a low-res placeholder image if there's a thumbnail available from the asset that can
+ // be shown to the user more quickly than the full-sized image.
+ if (mWallpaperAsset.hasLowResDataSource()) {
+ mWallpaperAsset.loadLowResDrawable(activity, mLowResImageView, Color.BLACK,
+ new WallpaperPreviewBitmapTransformation(activity.getApplicationContext(),
+ isRtl()));
+ }
+
+ mWallpaperAsset.decodeRawDimensions(getActivity(), dimensions -> {
+ // Don't continue loading the wallpaper if the Fragment is detached.
+ if (getActivity() == null) {
+ return;
+ }
+
+ // Return early and show a dialog if dimensions are null (signaling a decoding error).
+ if (dimensions == null) {
+ showLoadWallpaperErrorDialog();
+ return;
+ }
+
+ mRawWallpaperSize = dimensions;
+ setUpExploreIntent(ImagePreviewFragment.this::initFullResView);
+ });
+
+ // Configure loading indicator with a MaterialProgressDrawable.
+ setUpLoadingIndicator();
+
+ return view;
+ }
+
+ @Override
+ protected void setUpBottomSheetView(ViewGroup bottomSheet) {
+ // Nothing needed here.
+ }
+
+ private void setUpLoadingIndicator() {
+ Context context = requireContext();
+ mProgressDrawable = new MaterialProgressDrawable(context.getApplicationContext(),
+ mLoadingIndicator);
+ mProgressDrawable.setAlpha(255);
+ mProgressDrawable.setBackgroundColor(getResources().getColor(R.color.material_white_100,
+ context.getTheme()));
+ mProgressDrawable.setColorSchemeColors(getAttrColor(
+ new ContextThemeWrapper(context, getDeviceDefaultTheme()),
+ android.R.attr.colorAccent));
+ mProgressDrawable.updateSizes(MaterialProgressDrawable.LARGE);
+ mLoadingIndicator.setImageDrawable(mProgressDrawable);
+
+ // We don't want to show the spinner every time we load an image if it loads quickly;
+ // instead, only start showing the spinner if loading the image has taken longer than half
+ // of a second.
+ mLoadingIndicator.postDelayed(() -> {
+ if (mFullResImageView != null && !mFullResImageView.hasImage()
+ && !mTestingModeEnabled) {
+ mLoadingIndicator.setVisibility(View.VISIBLE);
+ mLoadingIndicator.setAlpha(1f);
+ if (mProgressDrawable != null) {
+ mProgressDrawable.start();
+ }
+ }
+ }, 500);
+ }
+
+ @Override
+ public void onClickOk() {
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mProgressDrawable != null) {
+ mProgressDrawable.stop();
+ }
+ mFullResImageView.recycle();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(mBottomSheet);
+ outState.putInt(KEY_BOTTOM_SHEET_STATE, bottomSheetBehavior.getState());
+ }
+
+ @Override
+ protected void setBottomSheetContentAlpha(float alpha) {
+ mExploreButton.setAlpha(alpha);
+ mAttributionTitle.setAlpha(alpha);
+ mAttributionSubtitle1.setAlpha(alpha);
+ mAttributionSubtitle2.setAlpha(alpha);
+ }
+
+ private void populateAttributionPane() {
+ final Context context = getContext();
+
+ final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(mBottomSheet);
+
+ List<String> attributions = mWallpaper.getAttributions(context);
+ if (attributions.size() > 0 && attributions.get(0) != null) {
+ mAttributionTitle.setText(attributions.get(0));
+ }
+
+ if (attributions.size() > 1 && attributions.get(1) != null) {
+ mAttributionSubtitle1.setVisibility(View.VISIBLE);
+ mAttributionSubtitle1.setText(attributions.get(1));
+ }
+
+ if (attributions.size() > 2 && attributions.get(2) != null) {
+ mAttributionSubtitle2.setVisibility(View.VISIBLE);
+ mAttributionSubtitle2.setText(attributions.get(2));
+ }
+
+ setUpSetWallpaperButton(mSetWallpaperButton);
+
+ setUpExploreButton(mExploreButton);
+
+ if (mExploreButton.getVisibility() == View.VISIBLE
+ && mSetWallpaperButton.getVisibility() == View.VISIBLE) {
+ mSpacer.setVisibility(View.VISIBLE);
+ } else {
+ mSpacer.setVisibility(View.GONE);
+ }
+
+ mBottomSheet.setVisibility(View.VISIBLE);
+
+ // Initialize the state of the BottomSheet based on the current state because if the initial
+ // and current state are the same, the state change listener won't fire and set the correct
+ // arrow asset and text alpha.
+ if (bottomSheetBehavior.getState() == STATE_EXPANDED) {
+ setPreviewChecked(false);
+ mAttributionTitle.setAlpha(1f);
+ mAttributionSubtitle1.setAlpha(1f);
+ mAttributionSubtitle2.setAlpha(1f);
+ } else {
+ setPreviewChecked(true);
+ mAttributionTitle.setAlpha(0f);
+ mAttributionSubtitle1.setAlpha(0f);
+ mAttributionSubtitle2.setAlpha(0f);
+ }
+
+ // Let the state change listener take care of animating a state change to the initial state
+ // if there's a state change.
+ bottomSheetBehavior.setState(mBottomSheetInitialState);
+ }
+
+ /**
+ * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
+ * initializing a zoom-scroll observer and click listener.
+ */
+ private void initFullResView() {
+ mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
+
+ // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
+ // for the image to load or a transparent one if a thumbnail already loaded.
+ Bitmap blackBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+ int color = (mLowResImageView.getDrawable() == null) ? Color.BLACK : Color.TRANSPARENT;
+ blackBitmap.setPixel(0, 0, color);
+ mFullResImageView.setImage(ImageSource.bitmap(blackBitmap));
+
+ // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
+ // (lower res) version of the image to be displayed.
+ Point targetPageBitmapSize = new Point(mRawWallpaperSize);
+ mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
+ pageBitmap -> {
+ // Check that the activity is still around since the decoding task started.
+ if (getActivity() == null) {
+ return;
+ }
+
+ // Some of these may be null depending on if the Fragment is paused, stopped,
+ // or destroyed.
+ if (mLoadingIndicator != null) {
+ mLoadingIndicator.setVisibility(View.GONE);
+ }
+ // The page bitmap may be null if there was a decoding error, so show an
+ // error dialog.
+ if (pageBitmap == null) {
+ showLoadWallpaperErrorDialog();
+ return;
+ }
+ if (mFullResImageView != null) {
+ // Set page bitmap.
+ mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
+
+ setDefaultWallpaperZoomAndScroll();
+ crossFadeInMosaicView();
+ }
+ if (mProgressDrawable != null) {
+ mProgressDrawable.stop();
+ }
+ getActivity().invalidateOptionsMenu();
+
+ populateAttributionPane();
+ });
+ }
+
+ /**
+ * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
+ * indicator.
+ */
+ private void crossFadeInMosaicView() {
+ long shortAnimationDuration = getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+
+ mFullResImageView.setAlpha(0f);
+ mFullResImageView.animate()
+ .alpha(1f)
+ .setDuration(shortAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Clear the thumbnail bitmap reference to save memory since it's no longer
+ // visible.
+ if (mLowResImageView != null) {
+ mLowResImageView.setImageBitmap(null);
+ }
+ }
+ });
+
+ mLoadingIndicator.animate()
+ .alpha(0f)
+ .setDuration(shortAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mLoadingIndicator != null) {
+ mLoadingIndicator.setVisibility(View.GONE);
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets the default wallpaper zoom and scroll position based on a "crop surface"
+ * (with extra width to account for parallax) superimposed on the screen. Shows as much of the
+ * wallpaper as possible on the crop surface and align screen to crop surface such that the
+ * default preview matches what would be seen by the user in the left-most home screen.
+ *
+ * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
+ * and rendered to the layout.
+ */
+ private void setDefaultWallpaperZoomAndScroll() {
+ // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
+ float defaultWallpaperZoom =
+ WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mDefaultCropSurfaceSize);
+ float minWallpaperZoom =
+ WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mScreenSize);
+
+ Point screenToCropSurfacePosition = WallpaperCropUtils.calculateCenterPosition(
+ mDefaultCropSurfaceSize, mScreenSize, true /* alignStart */, isRtl());
+ Point zoomedWallpaperSize = new Point(
+ Math.round(mRawWallpaperSize.x * defaultWallpaperZoom),
+ Math.round(mRawWallpaperSize.y * defaultWallpaperZoom));
+ Point cropSurfaceToWallpaperPosition = WallpaperCropUtils.calculateCenterPosition(
+ zoomedWallpaperSize, mDefaultCropSurfaceSize, false /* alignStart */, isRtl());
+
+ // Set min wallpaper zoom and max zoom on MosaicView widget.
+ mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
+ mFullResImageView.setMinScale(minWallpaperZoom);
+
+ // Set center to composite positioning between scaled wallpaper and screen.
+ PointF centerPosition = new PointF(
+ mRawWallpaperSize.x / 2f,
+ mRawWallpaperSize.y / 2f);
+ centerPosition.offset(-(screenToCropSurfacePosition.x + cropSurfaceToWallpaperPosition.x),
+ -(screenToCropSurfacePosition.y + cropSurfaceToWallpaperPosition.y));
+
+ mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
+ }
+
+ private Rect calculateCropRect() {
+ // Calculate Rect of wallpaper in physical pixel terms (i.e., scaled to current zoom).
+ float wallpaperZoom = mFullResImageView.getScale();
+ int scaledWallpaperWidth = (int) (mRawWallpaperSize.x * wallpaperZoom);
+ int scaledWallpaperHeight = (int) (mRawWallpaperSize.y * wallpaperZoom);
+ Rect rect = new Rect();
+ mFullResImageView.visibleFileRect(rect);
+ int scrollX = (int) (rect.left * wallpaperZoom);
+ int scrollY = (int) (rect.top * wallpaperZoom);
+
+ rect.set(0, 0, scaledWallpaperWidth, scaledWallpaperHeight);
+
+ Display defaultDisplay = requireActivity().getWindowManager().getDefaultDisplay();
+ Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(defaultDisplay);
+ // Crop rect should start off as the visible screen and then include extra width and height
+ // if available within wallpaper at the current zoom.
+ Rect cropRect = new Rect(scrollX, scrollY, scrollX + screenSize.x, scrollY + screenSize.y);
+
+ Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
+ getResources(), defaultDisplay);
+ int extraWidth = defaultCropSurfaceSize.x - screenSize.x;
+ int extraHeightTopAndBottom = (int) ((defaultCropSurfaceSize.y - screenSize.y) / 2f);
+
+ // Try to increase size of screenRect to include extra width depending on the layout
+ // direction.
+ if (isRtl()) {
+ 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.
+ int availableExtraHeightTop = cropRect.top - Math.max(
+ rect.top,
+ cropRect.top - extraHeightTopAndBottom);
+ int availableExtraHeightBottom = Math.min(
+ rect.bottom,
+ cropRect.bottom + extraHeightTopAndBottom) - cropRect.bottom;
+
+ int availableExtraHeightTopAndBottom =
+ Math.min(availableExtraHeightTop, availableExtraHeightBottom);
+ cropRect.top -= availableExtraHeightTopAndBottom;
+ cropRect.bottom += availableExtraHeightTopAndBottom;
+
+ return cropRect;
+ }
+
+ @Override
+ protected void setCurrentWallpaper(@Destination int destination) {
+ mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
+ destination, mFullResImageView.getScale(), calculateCropRect(),
+ new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ finishActivityWithResultOk();
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ showSetWallpaperErrorDialog(destination);
+ }
+ });
+ }
+}
diff --git a/src/com/android/wallpaper/picker/LivePreviewFragment.java b/src/com/android/wallpaper/picker/LivePreviewFragment.java
new file mode 100644
index 0000000..fee60a8
--- /dev/null
+++ b/src/com/android/wallpaper/picker/LivePreviewFragment.java
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2019 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 static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.service.wallpaper.IWallpaperConnection;
+import android.service.wallpaper.IWallpaperEngine;
+import android.service.wallpaper.IWallpaperService;
+import android.service.wallpaper.WallpaperService;
+import android.service.wallpaper.WallpaperSettingsActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager.LayoutParams;
+import android.view.animation.AnimationUtils;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.compat.BuildCompat;
+import com.android.wallpaper.model.LiveWallpaperInfo;
+import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
+import com.android.wallpaper.widget.MaterialProgressDrawable;
+
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.tabs.TabLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment which displays the UI for previewing an individual live wallpaper, its attribution
+ * information and settings slices if available.
+ */
+public class LivePreviewFragment extends PreviewFragment {
+
+ private static final String TAG = "LivePreviewFragment";
+
+ private static final String KEY_ACTION_DELETE_LIVE_WALLPAPER = "action_delete_live_wallpaper";
+ private static final String EXTRA_LIVE_WALLPAPER_INFO = "android.live_wallpaper.info";
+
+ /**
+ * Instance of {@link WallpaperConnection} used to bind to the live wallpaper service to show
+ * it in this preview fragment.
+ * @see IWallpaperConnection
+ */
+ private WallpaperConnection mWallpaperConnection;
+
+ private Intent mWallpaperIntent;
+ private Intent mDeleteIntent;
+ private Intent mSettingsIntent;
+
+ private List<Pair<String, View>> mPages;
+ private ImageView mLoadingIndicator;
+ private TextView mAttributionTitle;
+ private TextView mAttributionSubtitle1;
+ private TextView mAttributionSubtitle2;
+ private Button mExploreButton;
+ private Button mSetWallpaperButton;
+ private ViewPager mViewPager;
+ private TabLayout mTabLayout;
+ private SliceView mSettingsSliceView;
+ private LiveData<Slice> mSettingsLiveData;
+ private View mSpacer;
+ private View mLoadingScrim;
+ private MaterialProgressDrawable mProgressDrawable;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ android.app.WallpaperInfo info = mWallpaper.getWallpaperComponent();
+ mWallpaperIntent = new Intent(WallpaperService.SERVICE_INTERFACE)
+ .setClassName(info.getPackageName(), info.getServiceName());
+ setUpExploreIntent(null);
+
+ android.app.WallpaperInfo currentWallpaper =
+ WallpaperManager.getInstance(requireContext()).getWallpaperInfo();
+ String deleteAction = getDeleteAction(info.getServiceInfo(),
+ (currentWallpaper == null) ? null : currentWallpaper.getServiceInfo());
+
+ if (!TextUtils.isEmpty(deleteAction)) {
+ mDeleteIntent = new Intent(deleteAction);
+ mDeleteIntent.setPackage(info.getPackageName());
+ mDeleteIntent.putExtra(EXTRA_LIVE_WALLPAPER_INFO, info);
+ }
+
+ String settingsActivity = info.getSettingsActivity();
+ if (settingsActivity != null) {
+ mSettingsIntent = new Intent();
+ mSettingsIntent.setComponent(new ComponentName(info.getPackageName(),
+ settingsActivity));
+ mSettingsIntent.putExtra(WallpaperSettingsActivity.EXTRA_PREVIEW_MODE, true);
+ PackageManager pm = requireContext().getPackageManager();
+ ActivityInfo activityInfo = mSettingsIntent.resolveActivityInfo(pm, 0);
+ if (activityInfo == null) {
+ Log.i(TAG, "Couldn't find wallpaper settings activity: " + settingsActivity);
+ mSettingsIntent = null;
+ }
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mPages = new ArrayList<>();
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ if (view == null) {
+ return null;
+ }
+
+ Activity activity = requireActivity();
+
+ mLoadingScrim = view.findViewById(R.id.loading);
+ mLoadingIndicator = view.findViewById(R.id.loading_indicator);
+ setUpLoadingIndicator();
+
+ mWallpaperConnection = new WallpaperConnection(mWallpaperIntent, activity);
+ container.post(() -> {
+ if (!mWallpaperConnection.connect()) {
+ mWallpaperConnection = null;
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (mSettingsLiveData != null && mSettingsLiveData.hasObservers()) {
+ mSettingsLiveData.removeObserver(mSettingsSliceView);
+ mSettingsLiveData = null;
+ }
+ if (mWallpaperConnection != null) {
+ mWallpaperConnection.disconnect();
+ }
+ mWallpaperConnection = null;
+ super.onDestroy();
+ }
+
+ @Override
+ protected void setUpBottomSheetView(ViewGroup bottomSheet) {
+
+ initInfoPage();
+ initSettingsPage();
+
+ mViewPager = bottomSheet.findViewById(R.id.viewpager);
+ mTabLayout = bottomSheet.findViewById(R.id.tablayout);
+
+ // Create PagerAdapter
+ final PagerAdapter pagerAdapter = new PagerAdapter() {
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ final View page = mPages.get(position).second;
+ container.addView(page);
+ return page;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup container, int position,
+ @NonNull Object object) {
+ if (object instanceof View) {
+ container.removeView((View) object);
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mPages.size();
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ try {
+ return mPages.get(position).first;
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
+ return (view == object);
+ }
+ };
+
+ // Add OnPageChangeListener to re-measure ViewPager's height
+ mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ mViewPager.requestLayout();
+ }
+ });
+
+ // Set PagerAdapter
+ mViewPager.setAdapter(pagerAdapter);
+
+ // Make TabLayout visible if there are more than one page
+ if (mPages.size() > 1) {
+ mTabLayout.setVisibility(View.VISIBLE);
+ mTabLayout.setupWithViewPager(mViewPager);
+ }
+ mViewPager.setCurrentItem(0);
+ }
+
+ private void setUpLoadingIndicator() {
+ Context context = requireContext();
+ mProgressDrawable = new MaterialProgressDrawable(context.getApplicationContext(),
+ mLoadingIndicator);
+ mProgressDrawable.setAlpha(255);
+ mProgressDrawable.setBackgroundColor(getResources().getColor(R.color.material_white_100,
+ context.getTheme()));
+ mProgressDrawable.setColorSchemeColors(getAttrColor(
+ new ContextThemeWrapper(context, getDeviceDefaultTheme()),
+ android.R.attr.colorAccent));
+ mProgressDrawable.updateSizes(MaterialProgressDrawable.LARGE);
+ mLoadingIndicator.setImageDrawable(mProgressDrawable);
+
+ // We don't want to show the spinner every time we load a wallpaper if it loads quickly;
+ // instead, only start showing the spinner after 100 ms
+ mLoadingIndicator.postDelayed(() -> {
+ if ((mWallpaperConnection == null || !mWallpaperConnection.isEngineReady())
+ && !mTestingModeEnabled) {
+ mLoadingIndicator.setVisibility(View.VISIBLE);
+ mLoadingIndicator.setAlpha(1f);
+ if (mProgressDrawable != null) {
+ mProgressDrawable.start();
+ }
+ }
+ }, 100);
+ }
+
+ private void initInfoPage() {
+ View pageInfo = getLayoutInflater().inflate(R.layout.preview_page_info, null /* root */);
+
+ mAttributionTitle = pageInfo.findViewById(R.id.preview_attribution_pane_title);
+ mAttributionSubtitle1 = pageInfo.findViewById(R.id.preview_attribution_pane_subtitle1);
+ mAttributionSubtitle2 = pageInfo.findViewById(R.id.preview_attribution_pane_subtitle2);
+ mSpacer = pageInfo.findViewById(R.id.spacer);
+
+ mExploreButton = pageInfo.findViewById(R.id.preview_attribution_pane_explore_button);
+ mSetWallpaperButton = pageInfo.findViewById(
+ R.id.preview_attribution_pane_set_wallpaper_button);
+
+ mPages.add(Pair.create(getString(R.string.tab_info), pageInfo));
+ }
+
+ private void initSettingsPage() {
+ final Uri uriSettingsSlice = getSettingsSliceUri(mWallpaper.getWallpaperComponent());
+ if (uriSettingsSlice == null) {
+ return;
+ }
+
+ final View pageSettings = getLayoutInflater().inflate(R.layout.preview_page_settings,
+ null /* root */);
+
+ mSettingsSliceView = pageSettings.findViewById(R.id.settings_slice);
+ mSettingsSliceView.setMode(SliceView.MODE_LARGE);
+ mSettingsSliceView.setScrollable(false);
+
+ // Set LiveData for SliceView
+ mSettingsLiveData = SliceLiveData.fromUri(requireContext() /* context */, uriSettingsSlice);
+ mSettingsLiveData.observeForever(mSettingsSliceView);
+
+ mPages.add(Pair.create(getResources().getString(R.string.tab_customize), pageSettings));
+ }
+
+ private void populateAttributionPane() {
+ final Context context = getContext();
+
+ final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(mBottomSheet);
+
+ List<String> attributions = mWallpaper.getAttributions(context);
+ if (attributions.size() > 0 && attributions.get(0) != null) {
+ mAttributionTitle.setText(attributions.get(0));
+ }
+
+ if (mWallpaper.getWallpaperComponent().getShowMetadataInPreview()) {
+
+ if (attributions.size() > 1 && attributions.get(1) != null) {
+ mAttributionSubtitle1.setVisibility(View.VISIBLE);
+ mAttributionSubtitle1.setText(attributions.get(1));
+ }
+
+ if (attributions.size() > 2 && attributions.get(2) != null) {
+ mAttributionSubtitle2.setVisibility(View.VISIBLE);
+ mAttributionSubtitle2.setText(attributions.get(2));
+ }
+
+ } else {
+ mExploreIntent = null;
+ }
+
+ setUpSetWallpaperButton(mSetWallpaperButton);
+
+ setUpExploreButton(mExploreButton);
+
+ if (mExploreButton.getVisibility() == View.VISIBLE
+ && mSetWallpaperButton.getVisibility() == View.VISIBLE) {
+ mSpacer.setVisibility(View.VISIBLE);
+ } else {
+ mSpacer.setVisibility(View.GONE);
+ }
+
+ mBottomSheet.setVisibility(View.VISIBLE);
+
+ // Initialize the state of the BottomSheet based on the current state because if the initial
+ // and current state are the same, the state change listener won't fire and set the correct
+ // arrow asset and text alpha.
+ if (mBottomSheetInitialState == STATE_EXPANDED) {
+ setPreviewChecked(false);
+ mAttributionTitle.setAlpha(1f);
+ mAttributionSubtitle1.setAlpha(1f);
+ mAttributionSubtitle2.setAlpha(1f);
+ } else {
+ setPreviewChecked(true);
+ mAttributionTitle.setAlpha(0f);
+ mAttributionSubtitle1.setAlpha(0f);
+ mAttributionSubtitle2.setAlpha(0f);
+ }
+
+ bottomSheetBehavior.setState(mBottomSheetInitialState);
+ }
+
+ @SuppressLint("NewApi") //Already checking with isAtLeastQ
+ private Uri getSettingsSliceUri(android.app.WallpaperInfo info) {
+ if (BuildCompat.isAtLeastQ()) {
+ return info.getSettingsSliceUri();
+ }
+ return null;
+ }
+
+ @Override
+ protected int getLayoutResId() {
+ return R.layout.fragment_live_preview;
+ }
+
+ @Override
+ protected int getBottomSheetResId() {
+ return R.id.bottom_sheet;
+ }
+
+ @Override
+ protected void setCurrentWallpaper(int destination) {
+ mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, null,
+ destination, 0, null, new SetWallpaperCallback() {
+ @Override
+ public void onSuccess() {
+ finishActivityWithResultOk();
+ }
+
+ @Override
+ public void onError(@Nullable Throwable throwable) {
+ showSetWallpaperErrorDialog(destination);
+ }
+ });
+ }
+
+ @Override
+ protected void setBottomSheetContentAlpha(float alpha) {
+ mExploreButton.setAlpha(alpha);
+ mAttributionTitle.setAlpha(alpha);
+ mAttributionSubtitle1.setAlpha(alpha);
+ mAttributionSubtitle2.setAlpha(alpha);
+ }
+
+ @Override
+ protected void setUpExploreButton(Button exploreButton) {
+ super.setUpExploreButton(exploreButton);
+ if (exploreButton.getVisibility() != View.VISIBLE) {
+ return;
+ }
+ Context context = requireContext();
+ CharSequence exploreLabel = ((LiveWallpaperInfo) mWallpaper).getActionDescription(context);
+ if (!TextUtils.isEmpty(exploreLabel)) {
+ exploreButton.setText(exploreLabel);
+ }
+ }
+
+ @Nullable
+ private String getDeleteAction(ServiceInfo serviceInfo,
+ @Nullable ServiceInfo currentService) {
+ if (!isPackagePreInstalled(serviceInfo.applicationInfo)) {
+ Log.d(TAG, "This wallpaper is not pre-installed: " + serviceInfo.name);
+ return null;
+ }
+
+ // A currently set Live wallpaper should not be deleted.
+ if (currentService != null && TextUtils.equals(serviceInfo.name, currentService.name)) {
+ return null;
+ }
+
+ final Bundle metaData = serviceInfo.metaData;
+ if (metaData != null) {
+ return metaData.getString(KEY_ACTION_DELETE_LIVE_WALLPAPER);
+ }
+ return null;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mWallpaperConnection != null) {
+ mWallpaperConnection.setVisibility(true);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mWallpaperConnection != null) {
+ mWallpaperConnection.setVisibility(false);
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ menu.findItem(R.id.configure).setVisible(mSettingsIntent != null);
+ menu.findItem(R.id.delete_wallpaper).setVisible(mDeleteIntent != null);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if (id == R.id.configure) {
+ if (getActivity() != null) {
+ startActivity(mSettingsIntent);
+ return true;
+ }
+ } else if (id == R.id.delete_wallpaper) {
+ showDeleteConfirmDialog();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void showDeleteConfirmDialog() {
+ final AlertDialog alertDialog = new AlertDialog.Builder(
+ new ContextThemeWrapper(getContext(), getDeviceDefaultTheme()))
+ .setMessage(R.string.delete_wallpaper_confirmation)
+ .setPositiveButton(R.string.delete_live_wallpaper,
+ (dialog, which) -> deleteLiveWallpaper())
+ .setNegativeButton(android.R.string.cancel, null /* listener */)
+ .create();
+ alertDialog.show();
+ }
+
+ private void deleteLiveWallpaper() {
+ if (mDeleteIntent != null) {
+ requireContext().startService(mDeleteIntent);
+ finishActivityWithResultOk();
+ }
+ }
+
+ private boolean isPackagePreInstalled(ApplicationInfo info) {
+ if (info != null && (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private class WallpaperConnection extends IWallpaperConnection.Stub
+ implements ServiceConnection {
+ private final Activity mActivity;
+ private final Intent mIntent;
+ private IWallpaperService mService;
+ private IWallpaperEngine mEngine;
+ private boolean mConnected;
+ private boolean mIsVisible;
+ private boolean mIsEngineVisible;
+ private boolean mEngineReady;
+
+ WallpaperConnection(Intent intent, Activity activity) {
+ mActivity = activity;
+ mIntent = intent;
+ }
+
+ public boolean connect() {
+ synchronized (this) {
+ if (!mActivity.bindService(mIntent, this, Context.BIND_AUTO_CREATE)) {
+ return false;
+ }
+
+ mConnected = true;
+ return true;
+ }
+ }
+
+ public void disconnect() {
+ synchronized (this) {
+ mConnected = false;
+ if (mEngine != null) {
+ try {
+ mEngine.destroy();
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ mEngine = null;
+ }
+ try {
+ mActivity.unbindService(this);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Can't unbind wallpaper service. "
+ + "It might have crashed, just ignoring.", e);
+ }
+ mService = null;
+ }
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (mWallpaperConnection == this) {
+ mService = IWallpaperService.Stub.asInterface(service);
+ try {
+ View root = mActivity.getWindow().getDecorView();
+ int displayId = root.getDisplay().getDisplayId();
+ mService.attach(this, root.getWindowToken(),
+ LayoutParams.TYPE_APPLICATION_MEDIA,
+ true, root.getWidth(), root.getHeight(),
+ new Rect(0, 0, 0, 0), displayId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed attaching wallpaper; clearing", e);
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ mEngine = null;
+ if (mWallpaperConnection == this) {
+ Log.w(TAG, "Wallpaper service gone: " + name);
+ }
+ }
+
+ public void attachEngine(IWallpaperEngine engine, int displayId) {
+ synchronized (this) {
+ if (mConnected) {
+ mEngine = engine;
+ if (mIsVisible) {
+ setEngineVisibility(true);
+ }
+ } else {
+ try {
+ engine.destroy();
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ public ParcelFileDescriptor setWallpaper(String name) {
+ return null;
+ }
+
+ @Override
+ public void onWallpaperColorsChanged(WallpaperColors colors, int displayId)
+ throws RemoteException {
+
+ }
+
+ @Override
+ public void engineShown(IWallpaperEngine engine) {
+ mLoadingScrim.post(() -> {
+ mLoadingScrim.animate()
+ .alpha(0f)
+ .setDuration(220)
+ .setStartDelay(300)
+ .setInterpolator(AnimationUtils.loadInterpolator(mActivity,
+ android.R.interpolator.fast_out_linear_in))
+ .withEndAction(() -> {
+ if (mLoadingIndicator != null) {
+ mLoadingIndicator.setVisibility(View.GONE);
+ }
+ if (mProgressDrawable != null) {
+ mProgressDrawable.stop();
+ }
+ mLoadingScrim.setVisibility(View.INVISIBLE);
+ populateAttributionPane();
+ });
+ });
+ mEngineReady = true;
+ }
+
+ public boolean isEngineReady() {
+ return mEngineReady;
+ }
+
+ public void setVisibility(boolean visible) {
+ mIsVisible = visible;
+ setEngineVisibility(visible);
+ }
+
+ private void setEngineVisibility(boolean visible) {
+ if (mEngine != null && visible != mIsEngineVisible) {
+ try {
+ mEngine.setVisibility(visible);
+ mIsEngineVisible = visible;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure setting wallpaper visibility ", e);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/wallpaper/picker/PreviewFragment.java b/src/com/android/wallpaper/picker/PreviewFragment.java
index c698c8c..f1a1625 100755
--- a/src/com/android/wallpaper/picker/PreviewFragment.java
+++ b/src/com/android/wallpaper/picker/PreviewFragment.java
@@ -18,46 +18,33 @@ package com.android.wallpaper.picker;
import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED;
import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
-import android.view.ContextThemeWrapper;
-import android.view.Display;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.CallSuper;
+import androidx.annotation.IdRes;
import androidx.annotation.IntDef;
+import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
@@ -66,9 +53,6 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.wallpaper.R;
-import com.android.wallpaper.asset.Asset;
-import com.android.wallpaper.asset.Asset.BitmapReceiver;
-import com.android.wallpaper.asset.Asset.DimensionsReceiver;
import com.android.wallpaper.compat.BuildCompat;
import com.android.wallpaper.model.LiveWallpaperInfo;
import com.android.wallpaper.model.WallpaperInfo;
@@ -76,19 +60,10 @@ import com.android.wallpaper.module.ExploreIntentChecker;
import com.android.wallpaper.module.Injector;
import com.android.wallpaper.module.InjectorProvider;
import com.android.wallpaper.module.UserEventLogger;
-import com.android.wallpaper.module.WallpaperPersister;
import com.android.wallpaper.module.WallpaperPersister.Destination;
-import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
import com.android.wallpaper.module.WallpaperPreferences;
import com.android.wallpaper.module.WallpaperSetter;
-import com.android.wallpaper.util.ScreenSizeCalculator;
-import com.android.wallpaper.util.WallpaperCropUtils;
-import com.android.wallpaper.widget.MaterialProgressDrawable;
-
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.MemoryCategory;
-import com.davemorrissey.labs.subscaleview.ImageSource;
-import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
+
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetBehavior.State;
@@ -96,23 +71,22 @@ import java.util.Date;
import java.util.List;
/**
- * Fragment which displays the UI for previewing an individual wallpaper and its attribution
- * information.
+ * Base Fragment to display the UI for previewing an individual wallpaper
*/
-public class PreviewFragment extends Fragment implements
+public abstract class PreviewFragment extends Fragment implements
SetWallpaperDialogFragment.Listener, SetWallpaperErrorDialogFragment.Listener,
LoadWallpaperErrorDialogFragment.Listener {
/**
* User can view wallpaper and attributions in full screen, but "Set wallpaper" button is hidden.
*/
- public static final int MODE_VIEW_ONLY = 0;
+ static final int MODE_VIEW_ONLY = 0;
/**
* User can view wallpaper and attributions in full screen and click "Set wallpaper" to set the
* wallpaper with pan and crop position to the device.
*/
- public static final int MODE_CROP_AND_SET_WALLPAPER = 1;
+ static final int MODE_CROP_AND_SET_WALLPAPER = 1;
/**
* Possible preview modes for the fragment.
@@ -126,52 +100,56 @@ public class PreviewFragment extends Fragment implements
public static final String ARG_WALLPAPER = "wallpaper";
public static final String ARG_PREVIEW_MODE = "preview_mode";
public static final String ARG_TESTING_MODE_ENABLED = "testing_mode_enabled";
+
+ /**
+ * Creates and returns new instance of {@link ImagePreviewFragment} with the provided wallpaper
+ * set as an argument.
+ */
+ public static PreviewFragment newInstance(
+ WallpaperInfo wallpaperInfo, @PreviewMode int mode, boolean testingModeEnabled) {
+
+ boolean isLive = wallpaperInfo instanceof LiveWallpaperInfo;
+
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_WALLPAPER, wallpaperInfo);
+ args.putInt(ARG_PREVIEW_MODE, mode);
+ args.putBoolean(ARG_TESTING_MODE_ENABLED, testingModeEnabled);
+
+ PreviewFragment fragment = isLive ? new LivePreviewFragment() : new ImagePreviewFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
private static final String TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT =
"load_wallpaper_error_dialog";
private static final String TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT =
"set_wallpaper_error_dialog";
private static final int UNUSED_REQUEST_CODE = 1;
- private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
private static final String TAG = "PreviewFragment";
- private static final float PAGE_BITMAP_MAX_HEAP_RATIO = 0.25f;
- private static final String KEY_BOTTOM_SHEET_STATE = "key_bottom_sheet_state";
+ static final String KEY_BOTTOM_SHEET_STATE = "key_bottom_sheet_state";
@PreviewMode
- private int mPreviewMode;
+ protected int mPreviewMode;
/**
* When true, enables a test mode of operation -- in which certain UI features are disabled to
* allow for UI tests to run correctly. Works around issue in ProgressDialog currently where the
* dialog constantly keeps the UI thread alive and blocks a test forever.
*/
- private boolean mTestingModeEnabled;
+ protected boolean mTestingModeEnabled;
- protected SubsamplingScaleImageView mFullResImageView;
protected WallpaperInfo mWallpaper;
- private Asset mWallpaperAsset;
- private WallpaperSetter mWallpaperSetter;
- private UserEventLogger mUserEventLogger;
- private LinearLayout mBottomSheet;
- private TextView mAttributionTitle;
- private TextView mAttributionSubtitle1;
- private TextView mAttributionSubtitle2;
- private Button mAttributionExploreButton;
- private int mCurrentScreenOrientation;
- private Point mDefaultCropSurfaceSize;
- private Point mScreenSize;
- private Point mRawWallpaperSize; // Native size of wallpaper image.
- private ImageView mLoadingIndicator;
- private MaterialProgressDrawable mProgressDrawable;
- private ImageView mLowResImageView;
- private Button mSetWallpaperButton;
- private View mSpacer;
- private CheckBox mPreview;
+ protected WallpaperSetter mWallpaperSetter;
+ protected UserEventLogger mUserEventLogger;
+ protected ViewGroup mBottomSheet;
+
+ protected CheckBox mPreview;
@SuppressWarnings("RestrictTo")
@State
- private int mBottomSheetInitialState;
+ protected int mBottomSheetInitialState;
- private Intent mExploreIntent;
+ protected Intent mExploreIntent;
/**
* Staged error dialog fragments that were unable to be shown when the hosting activity didn't
@@ -180,23 +158,7 @@ public class PreviewFragment extends Fragment implements
private SetWallpaperErrorDialogFragment mStagedSetWallpaperErrorDialogFragment;
private LoadWallpaperErrorDialogFragment mStagedLoadWallpaperErrorDialogFragment;
- /**
- * Creates and returns new instance of {@link PreviewFragment} with the provided wallpaper set as
- * an argument.
- */
- public static PreviewFragment newInstance(
- WallpaperInfo wallpaperInfo, @PreviewMode int mode, boolean testingModeEnabled) {
- Bundle args = new Bundle();
- args.putParcelable(ARG_WALLPAPER, wallpaperInfo);
- args.putInt(ARG_PREVIEW_MODE, mode);
- args.putBoolean(ARG_TESTING_MODE_ENABLED, testingModeEnabled);
-
- PreviewFragment fragment = new PreviewFragment();
- fragment.setArguments(args);
- return fragment;
- }
-
- private static int getAttrColor(Context context, int attr) {
+ protected static int getAttrColor(Context context, int attr) {
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
int colorAccent = ta.getColor(0, 0);
ta.recycle();
@@ -208,12 +170,12 @@ public class PreviewFragment extends Fragment implements
super.onCreate(savedInstanceState);
Activity activity = getActivity();
- Context appContext = activity.getApplicationContext();
+ Context appContext = getContext().getApplicationContext();
Injector injector = InjectorProvider.getInjector();
mUserEventLogger = injector.getUserEventLogger(appContext);
mWallpaper = getArguments().getParcelable(ARG_WALLPAPER);
- mWallpaperAsset = mWallpaper.getAsset(appContext);
+
//noinspection ResourceType
mPreviewMode = getArguments().getInt(ARG_PREVIEW_MODE);
mTestingModeEnabled = getArguments().getBoolean(ARG_TESTING_MODE_ENABLED);
@@ -236,14 +198,18 @@ public class PreviewFragment extends Fragment implements
}
}
+ @LayoutRes
+ protected abstract int getLayoutResId();
+
@Override
+ @CallSuper
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_preview, container, false);
+ View view = inflater.inflate(getLayoutResId(), container, false);
// Set toolbar as the action bar.
Toolbar toolbar = view.findViewById(R.id.toolbar);
- AppCompatActivity activity = (AppCompatActivity) getActivity();
+ AppCompatActivity activity = (AppCompatActivity) requireActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setDisplayShowTitleEnabled(false);
@@ -270,18 +236,8 @@ public class PreviewFragment extends Fragment implements
R.dimen.preview_toolbar_set_wallpaper_button_end_padding),
/* bottom */ 0);
- mFullResImageView = view.findViewById(R.id.full_res_image);
- mLoadingIndicator = view.findViewById(R.id.loading_indicator);
-
- mBottomSheet = view.findViewById(R.id.bottom_sheet);
- mAttributionTitle = view.findViewById(R.id.preview_attribution_pane_title);
- mAttributionSubtitle1 = view.findViewById(R.id.preview_attribution_pane_subtitle1);
- mAttributionSubtitle2 = view.findViewById(R.id.preview_attribution_pane_subtitle2);
- mAttributionExploreButton = view.findViewById(
- R.id.preview_attribution_pane_explore_button);
- mLowResImageView = view.findViewById(R.id.low_res_image);
- mSetWallpaperButton = view.findViewById(R.id.preview_attribution_pane_set_wallpaper_button);
- mSpacer = view.findViewById(R.id.spacer);
+ mBottomSheet = view.findViewById(getBottomSheetResId());
+ setUpBottomSheetView(mBottomSheet);
// Workaround as we don't have access to bottomDialogCornerRadius, mBottomSheet radii are
// set to dialogCornerRadius by default.
@@ -294,93 +250,18 @@ public class PreviewFragment extends Fragment implements
bottomSheetBackground.setCornerRadii(radii);
mBottomSheet.setBackground(bottomSheetBackground);
- // Trim some memory from Glide to make room for the full-size image in this fragment.
- Glide.get(getActivity()).setMemoryCategory(MemoryCategory.LOW);
-
- mDefaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
- getResources(), getActivity().getWindowManager().getDefaultDisplay());
- mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
- getActivity().getWindowManager().getDefaultDisplay());
-
- // Load a low-res placeholder image if there's a thumbnail available from the asset that can be
- // shown to the user more quickly than the full-sized image.
- if (mWallpaperAsset.hasLowResDataSource()) {
- mWallpaperAsset.loadLowResDrawable(getActivity(), mLowResImageView, Color.BLACK,
- new WallpaperPreviewBitmapTransformation(getActivity().getApplicationContext(),
- isRtl()));
- }
-
- mWallpaperAsset.decodeRawDimensions(getActivity(), new DimensionsReceiver() {
- @Override
- public void onDimensionsDecoded(Point dimensions) {
- // Don't continue loading the wallpaper if the Fragment is detached.
- Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- // Return early and show a dialog if dimensions are null (signaling a decoding error).
- if (dimensions == null) {
- showLoadWallpaperErrorDialog();
- return;
- }
-
- mRawWallpaperSize = dimensions;
- ExploreIntentChecker intentChecker =
- InjectorProvider.getInjector().getExploreIntentChecker(activity);
- String actionUrl = mWallpaper.getActionUrl(activity);
- if (actionUrl != null && !actionUrl.isEmpty()) {
- Uri exploreUri = Uri.parse(mWallpaper.getActionUrl(activity));
-
- intentChecker.fetchValidActionViewIntent(exploreUri, exploreIntent -> {
- if (getActivity() == null) {
- return;
- }
-
- mExploreIntent = exploreIntent;
- initFullResView();
- });
- } else {
- initFullResView();
- }
- }
- });
-
- // Configure loading indicator with a MaterialProgressDrawable.
- mProgressDrawable = new MaterialProgressDrawable(getActivity().getApplicationContext(),
- mLoadingIndicator);
- mProgressDrawable.setAlpha(255);
- mProgressDrawable.setBackgroundColor(getResources().getColor(R.color.material_white_100,
- getContext().getTheme()));
- mProgressDrawable.setColorSchemeColors(getAttrColor(
- new ContextThemeWrapper(getContext(), getDeviceDefaultTheme()),
- android.R.attr.colorAccent));
- mProgressDrawable.updateSizes(MaterialProgressDrawable.LARGE);
- mLoadingIndicator.setImageDrawable(mProgressDrawable);
-
- // We don't want to show the spinner every time we load an image if it loads quickly; instead,
- // only start showing the spinner if loading the image has taken longer than half of a second.
- mLoadingIndicator.postDelayed(() -> {
- if (mFullResImageView != null && !mFullResImageView.hasImage()
- && !mTestingModeEnabled) {
- mLoadingIndicator.setVisibility(View.VISIBLE);
- mLoadingIndicator.setAlpha(1f);
- if (mProgressDrawable != null) {
- mProgressDrawable.start();
- }
- }
- }, 500);
-
-
- mBottomSheetInitialState = (savedInstanceState == null)
- ? STATE_EXPANDED
- : savedInstanceState.getInt(KEY_BOTTOM_SHEET_STATE,
- STATE_EXPANDED);
+ mBottomSheetInitialState = (savedInstanceState == null) ? STATE_EXPANDED
+ : savedInstanceState.getInt(KEY_BOTTOM_SHEET_STATE, STATE_EXPANDED);
setUpBottomSheetListeners();
return view;
}
+ protected abstract void setUpBottomSheetView(ViewGroup bottomSheet);
+
+ @IdRes
+ protected abstract int getBottomSheetResId();
+
protected int getDeviceDefaultTheme() {
return android.R.style.Theme_DeviceDefault;
}
@@ -398,12 +279,12 @@ public class PreviewFragment extends Fragment implements
// allow committing fragment transactions.
if (mStagedLoadWallpaperErrorDialogFragment != null) {
mStagedLoadWallpaperErrorDialogFragment.show(
- getFragmentManager(), TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ requireFragmentManager(), TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT);
mStagedLoadWallpaperErrorDialogFragment = null;
}
if (mStagedSetWallpaperErrorDialogFragment != null) {
mStagedSetWallpaperErrorDialogFragment.show(
- getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ requireFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
mStagedSetWallpaperErrorDialogFragment = null;
}
}
@@ -428,20 +309,20 @@ public class PreviewFragment extends Fragment implements
// the IndividualPreviewActivity, the "My photos" selection (by way of
// TopLevelPickerActivity), or from a system "crop and set wallpaper" intent.
// Therefore, handle the Up button as a global Back.
- getActivity().onBackPressed();
+ requireActivity().onBackPressed();
return true;
}
return false;
}
- protected void setupPreviewMenu(Menu menu) {
+ private void setupPreviewMenu(Menu menu) {
mPreview = (CheckBox) menu.findItem(R.id.preview).getActionView();
mPreview.setChecked(mBottomSheetInitialState == STATE_COLLAPSED);
mPreview.setOnClickListener(this::setPreviewBehavior);
}
- private void setPreviewChecked(boolean checked) {
+ protected void setPreviewChecked(boolean checked) {
if (mPreview != null) {
mPreview.setChecked(checked);
int resId = checked ? R.string.expand_attribution_panel
@@ -450,7 +331,7 @@ public class PreviewFragment extends Fragment implements
}
}
- private void setPreviewBehavior(final View v) {
+ private void setPreviewBehavior(View v) {
CheckBox checkbox = (CheckBox) v;
BottomSheetBehavior<?> behavior = BottomSheetBehavior.from(mBottomSheet);
@@ -461,6 +342,61 @@ public class PreviewFragment extends Fragment implements
}
}
+ protected void setUpSetWallpaperButton(Button setWallpaperButton) {
+ if (mPreviewMode == MODE_VIEW_ONLY) {
+ setWallpaperButton.setVisibility(View.GONE);
+ } else {
+ setWallpaperButton.setVisibility(View.VISIBLE);
+ setWallpaperButton.setOnClickListener(this::onSetWallpaperClicked);
+ }
+ }
+
+ protected void setUpExploreButton(Button exploreButton) {
+ exploreButton.setVisibility(View.GONE);
+ if (mExploreIntent == null) {
+ return;
+ }
+ Context context = requireContext();
+ exploreButton.setVisibility(View.VISIBLE);
+ exploreButton.setText(context.getString(
+ mWallpaper.getActionLabelRes(context)));
+
+ exploreButton.setOnClickListener(view -> {
+ mUserEventLogger.logActionClicked(mWallpaper.getCollectionId(context),
+ mWallpaper.getActionLabelRes(context));
+
+ startActivity(mExploreIntent);
+ });
+ }
+
+ protected void setUpExploreIntent(@Nullable Runnable callback) {
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+ String actionUrl = mWallpaper.getActionUrl(context);
+ if (actionUrl != null && !actionUrl.isEmpty()) {
+ Uri exploreUri = Uri.parse(mWallpaper.getActionUrl(context));
+ ExploreIntentChecker intentChecker =
+ InjectorProvider.getInjector().getExploreIntentChecker(context);
+
+ intentChecker.fetchValidActionViewIntent(exploreUri, exploreIntent -> {
+ if (getActivity() == null) {
+ return;
+ }
+
+ mExploreIntent = exploreIntent;
+ if (callback != null) {
+ callback.run();
+ }
+ });
+ } else {
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ }
+
@Override
public void onSet(int destination) {
setCurrentWallpaper(destination);
@@ -483,10 +419,6 @@ public class PreviewFragment extends Fragment implements
public void onDestroy() {
super.onDestroy();
mWallpaperSetter.cleanUp();
- if (mProgressDrawable != null) {
- mProgressDrawable.stop();
- }
- mFullResImageView.recycle();
}
@Override
@@ -498,41 +430,8 @@ public class PreviewFragment extends Fragment implements
}
private void onSetWallpaperClicked(View button) {
- if (BuildCompat.isAtLeastN()) {
- mWallpaperSetter.requestDestination(getContext(), getFragmentManager(), this,
- mWallpaper instanceof LiveWallpaperInfo);
- } else {
- setCurrentWallpaper(WallpaperPersister.DEST_HOME_SCREEN);
- }
- }
-
- /**
- * Returns a zoom level that is similar to the actual zoom, but that is exactly 0.5 ** n for some
- * integer n. This is useful for downsampling a bitmap--we want to see the bitmap at full detail,
- * or downsampled to 1 in every 2 pixels, or 1 in 4, and so on, depending on the zoom.
- */
- private static float getDownsampleZoom(float actualZoom) {
- if (actualZoom > 1) {
- // Very zoomed in, but we can't sample more than 1 pixel per pixel.
- return 1.0f;
- }
- float lower = 1.0f / roundUpToPower2((int) Math.ceil(1 / actualZoom));
- float upper = lower * 2;
- return nearestValue(actualZoom, lower, upper);
- }
-
- /**
- * Returns the integer rounded up to the next power of 2.
- */
- private static int roundUpToPower2(int value) {
- return 1 << (32 - Integer.numberOfLeadingZeros(value - 1));
- }
-
- /**
- * Returns the closer of two values a and b to the given value.
- */
- private static float nearestValue(float value, float a, float b) {
- return Math.abs(a - value) < Math.abs(b - value) ? a : b;
+ mWallpaperSetter.requestDestination(getContext(), getFragmentManager(), this,
+ mWallpaper instanceof LiveWallpaperInfo);
}
private void setUpBottomSheetListeners() {
@@ -554,6 +453,8 @@ public class PreviewFragment extends Fragment implements
case STATE_EXPANDED:
setPreviewChecked(false /* checked */);
break;
+ default:
+ Log.v(TAG, "Ignoring BottomSheet state: " + newState);
}
}
@@ -565,264 +466,13 @@ public class PreviewFragment extends Fragment implements
} else {
alpha = 1f - slideOffset;
}
- mAttributionTitle.setAlpha(alpha);
- mAttributionSubtitle1.setAlpha(alpha);
- mAttributionSubtitle2.setAlpha(alpha);
- mAttributionExploreButton.setAlpha(alpha);
+ setBottomSheetContentAlpha(alpha);
}
});
}
- private boolean isWallpaperLoaded() {
- return mFullResImageView.hasImage();
- }
-
- private void populateAttributionPane() {
- final Context context = getContext();
-
- final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(mBottomSheet);
-
- List<String> attributions = mWallpaper.getAttributions(context);
- if (attributions.size() > 0 && attributions.get(0) != null) {
- mAttributionTitle.setText(attributions.get(0));
- }
-
- if (attributions.size() > 1 && attributions.get(1) != null) {
- mAttributionSubtitle1.setVisibility(View.VISIBLE);
- mAttributionSubtitle1.setText(attributions.get(1));
- }
-
- if (attributions.size() > 2 && attributions.get(2) != null) {
- mAttributionSubtitle2.setVisibility(View.VISIBLE);
- mAttributionSubtitle2.setText(attributions.get(2));
- }
-
- if (mPreviewMode == MODE_CROP_AND_SET_WALLPAPER) {
- mSetWallpaperButton.setVisibility(View.VISIBLE);
- mSetWallpaperButton.setOnClickListener(this::onSetWallpaperClicked);
- } else {
- mSetWallpaperButton.setVisibility(View.GONE);
- }
-
- String actionUrl = mWallpaper.getActionUrl(context);
-
- mAttributionExploreButton.setVisibility(View.GONE);
- if (actionUrl != null && !actionUrl.isEmpty()) {
- if (mExploreIntent != null) {
- mAttributionExploreButton.setVisibility(View.VISIBLE);
- mAttributionExploreButton.setText(context.getString(
- mWallpaper.getActionLabelRes(context)));
-
- mAttributionExploreButton.setOnClickListener(view -> {
- mUserEventLogger.logActionClicked(mWallpaper.getCollectionId(context),
- mWallpaper.getActionLabelRes(context));
-
- startActivity(mExploreIntent);
- });
- }
- }
-
- if (mAttributionExploreButton.getVisibility() == View.VISIBLE
- && mSetWallpaperButton.getVisibility() == View.VISIBLE) {
- mSpacer.setVisibility(View.VISIBLE);
- } else {
- mSpacer.setVisibility(View.GONE);
- }
-
- mBottomSheet.setVisibility(View.VISIBLE);
-
- // Initialize the state of the BottomSheet based on the current state because if the initial
- // and current state are the same, the state change listener won't fire and set the correct
- // arrow asset and text alpha.
- if (bottomSheetBehavior.getState() == STATE_EXPANDED) {
- setPreviewChecked(false);
- mAttributionTitle.setAlpha(1f);
- mAttributionSubtitle1.setAlpha(1f);
- mAttributionSubtitle2.setAlpha(1f);
- } else {
- setPreviewChecked(true);
- mAttributionTitle.setAlpha(0f);
- mAttributionSubtitle1.setAlpha(0f);
- mAttributionSubtitle2.setAlpha(0f);
- }
-
- // Let the state change listener take care of animating a state change to the initial state
- // if there's a state change.
- bottomSheetBehavior.setState(mBottomSheetInitialState);
- }
-
- /**
- * Initializes MosaicView by initializing tiling, setting a fallback page bitmap, and
- * initializing a zoom-scroll observer and click listener.
- */
- private void initFullResView() {
- mFullResImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
-
- // Set a solid black "page bitmap" so MosaicView draws a black background while waiting
- // for the image to load or a transparent one if a thumbnail already loaded.
- Bitmap blackBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
- int color = (mLowResImageView.getDrawable() == null) ? Color.BLACK : Color.TRANSPARENT;
- blackBitmap.setPixel(0, 0, color);
- mFullResImageView.setImage(ImageSource.bitmap(blackBitmap));
-
- // Then set a fallback "page bitmap" to cover the whole MosaicView, which is an actual
- // (lower res) version of the image to be displayed.
- Point targetPageBitmapSize = new Point(mRawWallpaperSize);
- mWallpaperAsset.decodeBitmap(targetPageBitmapSize.x, targetPageBitmapSize.y,
- new BitmapReceiver() {
- @Override
- public void onBitmapDecoded(Bitmap pageBitmap) {
- // Check that the activity is still around since the decoding task started.
- if (getActivity() == null) {
- return;
- }
-
- // Some of these may be null depending on if the Fragment is paused, stopped,
- // or destroyed.
- if (mLoadingIndicator != null) {
- mLoadingIndicator.setVisibility(View.GONE);
- }
- // The page bitmap may be null if there was a decoding error, so show an
- // error dialog.
- if (pageBitmap == null) {
- showLoadWallpaperErrorDialog();
- return;
- }
- if (mFullResImageView != null) {
- // Set page bitmap.
- mFullResImageView.setImage(ImageSource.bitmap(pageBitmap));
-
- setDefaultWallpaperZoomAndScroll();
- crossFadeInMosaicView();
- }
- if (mProgressDrawable != null) {
- mProgressDrawable.stop();
- }
- getActivity().invalidateOptionsMenu();
-
- populateAttributionPane();
- }
- });
- }
+ protected void setBottomSheetContentAlpha(float alpha) {
- /**
- * Makes the MosaicView visible with an alpha fade-in animation while fading out the loading
- * indicator.
- */
- private void crossFadeInMosaicView() {
- long shortAnimationDuration = getResources().getInteger(
- android.R.integer.config_shortAnimTime);
-
- mFullResImageView.setAlpha(0f);
- mFullResImageView.animate()
- .alpha(1f)
- .setDuration(shortAnimationDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Clear the thumbnail bitmap reference to save memory since it's no longer
- // visible.
- if (mLowResImageView != null) {
- mLowResImageView.setImageBitmap(null);
- }
- }
- });
-
- mLoadingIndicator.animate()
- .alpha(0f)
- .setDuration(shortAnimationDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mLoadingIndicator != null) {
- mLoadingIndicator.setVisibility(View.GONE);
- }
- }
- });
- }
-
- /**
- * Sets the default wallpaper zoom and scroll position based on a "crop surface"
- * (with extra width to account for parallax) superimposed on the screen. Shows as much of the
- * wallpaper as possible on the crop surface and align screen to crop surface such that the
- * default preview matches what would be seen by the user in the left-most home screen.
- *
- * <p>This method is called once in the Fragment lifecycle after the wallpaper asset has loaded
- * and rendered to the layout.
- */
- private void setDefaultWallpaperZoomAndScroll() {
- // Determine minimum zoom to fit maximum visible area of wallpaper on crop surface.
- float defaultWallpaperZoom =
- WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mDefaultCropSurfaceSize);
- float minWallpaperZoom =
- WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mScreenSize);
-
- Point screenToCropSurfacePosition = WallpaperCropUtils.calculateCenterPosition(
- mDefaultCropSurfaceSize, mScreenSize, true /* alignStart */, isRtl());
- Point zoomedWallpaperSize = new Point(
- Math.round(mRawWallpaperSize.x * defaultWallpaperZoom),
- Math.round(mRawWallpaperSize.y * defaultWallpaperZoom));
- Point cropSurfaceToWallpaperPosition = WallpaperCropUtils.calculateCenterPosition(
- zoomedWallpaperSize, mDefaultCropSurfaceSize, false /* alignStart */, isRtl());
-
- // Set min wallpaper zoom and max zoom on MosaicView widget.
- mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
- mFullResImageView.setMinScale(minWallpaperZoom);
-
- // Set center to composite positioning between scaled wallpaper and screen.
- PointF centerPosition = new PointF(
- mRawWallpaperSize.x / 2f,
- mRawWallpaperSize.y / 2f);
- centerPosition.offset( - (screenToCropSurfacePosition.x + cropSurfaceToWallpaperPosition.x),
- - (screenToCropSurfacePosition.y + cropSurfaceToWallpaperPosition.y));
-
- mFullResImageView.setScaleAndCenter(minWallpaperZoom, centerPosition);
- }
-
- protected Rect calculateCropRect() {
- // Calculate Rect of wallpaper in physical pixel terms (i.e., scaled to current zoom).
- float wallpaperZoom = mFullResImageView.getScale();
- int scaledWallpaperWidth = (int) (mRawWallpaperSize.x * wallpaperZoom);
- int scaledWallpaperHeight = (int) (mRawWallpaperSize.y * wallpaperZoom);
- Rect rect = new Rect();
- mFullResImageView.visibleFileRect(rect);
- int scrollX = (int) (rect.left * wallpaperZoom);
- int scrollY = (int) (rect.top * wallpaperZoom);
-
- rect.set(0, 0, scaledWallpaperWidth, scaledWallpaperHeight);
- Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
- getActivity().getWindowManager().getDefaultDisplay());
- // Crop rect should start off as the visible screen and then include extra width and height
- // if available within wallpaper at the current zoom.
- Rect cropRect = new Rect(scrollX, scrollY, scrollX + screenSize.x, scrollY + screenSize.y);
-
- Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
- getResources(), getActivity().getWindowManager().getDefaultDisplay());
- int extraWidth = defaultCropSurfaceSize.x - screenSize.x;
- int extraHeightTopAndBottom = (int) ((defaultCropSurfaceSize.y - screenSize.y) / 2f);
-
- // Try to increase size of screenRect to include extra width depending on the layout
- // direction.
- if (isRtl()) {
- 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.
- int availableExtraHeightTop = cropRect.top - Math.max(
- rect.top,
- cropRect.top - extraHeightTopAndBottom);
- int availableExtraHeightBottom = Math.min(
- rect.bottom,
- cropRect.bottom + extraHeightTopAndBottom) - cropRect.bottom;
-
- int availableExtraHeightTopAndBottom =
- Math.min(availableExtraHeightTop, availableExtraHeightBottom);
- cropRect.top -= availableExtraHeightTopAndBottom;
- cropRect.bottom += availableExtraHeightTopAndBottom;
-
- return cropRect;
}
/**
@@ -830,35 +480,22 @@ public class PreviewFragment extends Fragment implements
*
* @param destination The wallpaper destination i.e. home vs. lockscreen vs. both.
*/
- private void setCurrentWallpaper(@Destination final int destination) {
- mWallpaperSetter.setCurrentWallpaper(getActivity(), mWallpaper, mWallpaperAsset,
- destination, mFullResImageView.getScale(), calculateCropRect(),
- new SetWallpaperCallback() {
- @Override
- public void onSuccess() {
- finishActivityWithResultOk();
- }
-
- @Override
- public void onError(@Nullable Throwable throwable) {
- showSetWallpaperErrorDialog(destination);
- }
- });
- }
+ protected abstract void setCurrentWallpaper(@Destination int destination);
- private void finishActivityWithResultOk() {
+ protected void finishActivityWithResultOk() {
+ Activity activity = requireActivity();
try {
- Toast.makeText(
- getActivity(), R.string.wallpaper_set_successfully_message, Toast.LENGTH_SHORT).show();
+ Toast.makeText(activity,
+ R.string.wallpaper_set_successfully_message, Toast.LENGTH_SHORT).show();
} catch (NotFoundException e) {
Log.e(TAG, "Could not show toast " + e);
}
- getActivity().overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
- getActivity().setResult(Activity.RESULT_OK);
- getActivity().finish();
+ activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
+ activity.setResult(Activity.RESULT_OK);
+ activity.finish();
}
- private void showSetWallpaperErrorDialog(@Destination int wallpaperDestination) {
+ protected void showSetWallpaperErrorDialog(@Destination int wallpaperDestination) {
SetWallpaperErrorDialogFragment newFragment = SetWallpaperErrorDialogFragment.newInstance(
R.string.set_wallpaper_error_message, wallpaperDestination);
newFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
@@ -866,9 +503,9 @@ public class PreviewFragment extends Fragment implements
// Show 'set wallpaper' error dialog now if it's safe to commit fragment transactions,
// otherwise stage it for later when the hosting activity is in a state to commit fragment
// transactions.
- BasePreviewActivity activity = (BasePreviewActivity) getActivity();
+ BasePreviewActivity activity = (BasePreviewActivity) requireActivity();
if (activity.isSafeToCommitFragmentTransaction()) {
- newFragment.show(getFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ newFragment.show(requireFragmentManager(), TAG_SET_WALLPAPER_ERROR_DIALOG_FRAGMENT);
} else {
mStagedSetWallpaperErrorDialogFragment = newFragment;
}
@@ -878,17 +515,16 @@ public class PreviewFragment extends Fragment implements
* Shows 'load wallpaper' error dialog now or stage it to be shown when the hosting activity is
* in a state that allows committing fragment transactions.
*/
- private void showLoadWallpaperErrorDialog() {
+ protected void showLoadWallpaperErrorDialog() {
LoadWallpaperErrorDialogFragment dialogFragment =
LoadWallpaperErrorDialogFragment.newInstance();
- dialogFragment.setTargetFragment(PreviewFragment.this, UNUSED_REQUEST_CODE);
+ dialogFragment.setTargetFragment(this, UNUSED_REQUEST_CODE);
// Show 'load wallpaper' error dialog now or stage it to be shown when the hosting
// activity is in a state that allows committing fragment transactions.
BasePreviewActivity activity = (BasePreviewActivity) getActivity();
if (activity != null && activity.isSafeToCommitFragmentTransaction()) {
- dialogFragment.show(PreviewFragment.this.getFragmentManager(),
- TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT);
+ dialogFragment.show(requireFragmentManager(), TAG_LOAD_WALLPAPER_ERROR_DIALOG_FRAGMENT);
} else {
mStagedLoadWallpaperErrorDialogFragment = dialogFragment;
}
@@ -903,59 +539,10 @@ public class PreviewFragment extends Fragment implements
}
/**
- * Gets the appropriate ActivityInfo orientation for the current configuration orientation to
- * enable locking screen rotation at API levels lower than 18.
- */
- @ActivityInfoScreenOrientation
- private int getCompatActivityInfoOrientation() {
- int configOrientation = getResources().getConfiguration().orientation;
- final Display display = getActivity().getWindowManager().getDefaultDisplay();
- int naturalOrientation = Configuration.ORIENTATION_LANDSCAPE;
- switch (display.getRotation()) {
- case Surface.ROTATION_0:
- case Surface.ROTATION_180:
- // We are currently in the same basic orientation as the natural orientation.
- naturalOrientation = configOrientation;
- break;
- case Surface.ROTATION_90:
- case Surface.ROTATION_270:
- // We are currently in the other basic orientation to the natural orientation.
- naturalOrientation = (configOrientation == Configuration.ORIENTATION_LANDSCAPE)
- ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- break;
- default:
- // continue below
- }
-
- // Since the map starts at portrait, we need to offset if this device's natural orientation
- // is landscape.
- int indexOffset = 0;
- if (naturalOrientation == Configuration.ORIENTATION_LANDSCAPE) {
- indexOffset = 1;
- }
-
- switch ((display.getRotation() + indexOffset) % 4) {
- case 0:
- return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- case 1:
- return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- case 2:
- return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- case 3:
- return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
- default:
- Log.e(TAG, "Display rotation did not correspond to a valid ActivityInfo orientation"
- + "with display rotation: " + display.getRotation() + " and index offset: "
- + indexOffset + ".");
- return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- }
- }
-
- /**
* Returns whether layout direction is RTL (or false for LTR). Since native RTL layout support
* was added in API 17, returns false for versions lower than 17.
*/
- private boolean isRtl() {
+ protected boolean isRtl() {
return getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
}
diff --git a/src/com/android/wallpaper/picker/StartRotationDialogFragment.java b/src/com/android/wallpaper/picker/StartRotationDialogFragment.java
index d5fd017..f0e4dcd 100755
--- a/src/com/android/wallpaper/picker/StartRotationDialogFragment.java
+++ b/src/com/android/wallpaper/picker/StartRotationDialogFragment.java
@@ -29,8 +29,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
-import androidx.appcompat.view.ContextThemeWrapper;
import androidx.fragment.app.DialogFragment;
import com.android.wallpaper.R;
@@ -42,29 +40,14 @@ import com.android.wallpaper.module.InjectorProvider;
*/
public class StartRotationDialogFragment extends DialogFragment {
private static final String KEY_IS_WIFI_ONLY_CHECKED = "key_is_wifi_only_checked";
- private static final String KEY_IS_LIVE_WALLPAPER_PREVIEW_NEEDED = "key_is_live_wallpaper_needed";
private static final boolean DEFAULT_IS_WIFI_ONLY = true;
private boolean mIsWifiOnlyChecked;
- private boolean mIsLiveWallpaperPreviewNeeded;
-
- public static StartRotationDialogFragment newInstance(boolean isLiveWallpaperPreviewNeeded) {
- StartRotationDialogFragment dialogFragment = new StartRotationDialogFragment();
- Bundle args = new Bundle();
- args.putBoolean(KEY_IS_LIVE_WALLPAPER_PREVIEW_NEEDED, isLiveWallpaperPreviewNeeded);
- dialogFragment.setArguments(args);
- return dialogFragment;
- }
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Bundle args = getArguments();
- if (args != null) {
- mIsLiveWallpaperPreviewNeeded = args.getBoolean(KEY_IS_LIVE_WALLPAPER_PREVIEW_NEEDED);
- }
-
if (savedInstanceState == null) {
mIsWifiOnlyChecked = DEFAULT_IS_WIFI_ONLY;
} else {
@@ -117,14 +100,10 @@ public class StartRotationDialogFragment extends DialogFragment {
}
private int getBodyTextResourceId() {
- return mIsLiveWallpaperPreviewNeeded
- ? R.string.start_rotation_dialog_body_live_wallpaper_needed
- : R.string.start_rotation_dialog_body;
+ return R.string.start_rotation_dialog_body;
}
private int getPositiveButtonTextResourceId() {
- return mIsLiveWallpaperPreviewNeeded
- ? R.string.start_rotation_dialog_continue
- : android.R.string.ok;
+ return android.R.string.ok;
}
}
diff --git a/src/com/android/wallpaper/picker/individual/IndividualPickerActivity.java b/src/com/android/wallpaper/picker/individual/IndividualPickerActivity.java
index 367181a..de5ba84 100755
--- a/src/com/android/wallpaper/picker/individual/IndividualPickerActivity.java
+++ b/src/com/android/wallpaper/picker/individual/IndividualPickerActivity.java
@@ -16,8 +16,6 @@
package com.android.wallpaper.picker.individual;
import android.app.Activity;
-import android.app.WallpaperManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources.NotFoundException;
@@ -44,12 +42,9 @@ import com.android.wallpaper.model.PickerIntentFactory;
import com.android.wallpaper.model.WallpaperInfo;
import com.android.wallpaper.module.Injector;
import com.android.wallpaper.module.InjectorProvider;
-import com.android.wallpaper.module.LiveWallpaperStatusChecker;
-import com.android.wallpaper.module.NoBackupImageWallpaper;
import com.android.wallpaper.module.WallpaperPersister;
import com.android.wallpaper.picker.BaseActivity;
import com.android.wallpaper.picker.PreviewActivity.PreviewActivityIntentFactory;
-import com.android.wallpaper.util.ActivityUtils;
import com.android.wallpaper.util.DiskBasedLogger;
/**
@@ -61,13 +56,11 @@ public class IndividualPickerActivity extends BaseActivity {
private static final String EXTRA_CATEGORY_COLLECTION_ID =
"com.android.wallpaper.category_collection_id";
private static final int PREVIEW_WALLPAPER_REQUEST_CODE = 0;
- private static final int NO_BACKUP_IMAGE_WALLPAPER_REQUEST_CODE = 1;
private static final int PREVIEW_LIVEWALLPAPER_REQUEST_CODE = 2;
private static final String KEY_CATEGORY_COLLECTION_ID = "key_category_collection_id";
private InlinePreviewIntentFactory mPreviewIntentFactory;
private WallpaperPersister mWallpaperPersister;
- private LiveWallpaperStatusChecker mLiveWallpaperStatusChecker;
private Category mCategory;
private String mCategoryCollectionId;
@@ -83,7 +76,6 @@ public class IndividualPickerActivity extends BaseActivity {
mPreviewIntentFactory = new PreviewActivityIntentFactory();
Injector injector = InjectorProvider.getInjector();
mWallpaperPersister = injector.getWallpaperPersister(this);
- mLiveWallpaperStatusChecker = injector.getLiveWallpaperStatusChecker(this);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
@@ -160,8 +152,8 @@ public class IndividualPickerActivity extends BaseActivity {
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
- // Handle Up as a Global back since the only entry point to IndividualPickerActivity is from
- // TopLevelPickerActivity.
+ // Handle Up as a Global back since the only entry point to IndividualPickerActivity is
+ // from TopLevelPickerActivity.
onBackPressed();
return true;
}
@@ -184,18 +176,6 @@ public class IndividualPickerActivity extends BaseActivity {
finishWithResultOk(shouldShowMessage);
}
break;
-
- case NO_BACKUP_IMAGE_WALLPAPER_REQUEST_CODE:
- // User clicked "Set wallpaper" in live wallpaper preview UI.
- // NOTE: Don't check for the result code prior to KitKat MR2 because a bug on those versions
- // caused the result code to be discarded from LivePicker so we can't rely on it.
- if ((!BuildCompat.isAtLeastL() || resultCode == Activity.RESULT_OK)
- && mLiveWallpaperStatusChecker.isNoBackupImageWallpaperSet()
- && mCategory.getWallpaperRotationInitializer().startRotation(getApplicationContext())) {
- finishWithResultOk(true);
- }
- break;
-
default:
Log.e(TAG, "Invalid request code: " + requestCode);
}
@@ -211,18 +191,6 @@ public class IndividualPickerActivity extends BaseActivity {
: PREVIEW_WALLPAPER_REQUEST_CODE);
}
- /**
- * Shows the system live wallpaper preview for the {@link NoBackupImageWallpaper} which is used to
- * draw rotating wallpapers on pre-N Android builds.
- */
- public void showNoBackupImageWallpaperPreview() {
- Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
- ComponentName componentName = new ComponentName(this, NoBackupImageWallpaper.class);
- intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, componentName);
- ActivityUtils.startActivityForResultSafely(
- this, intent, NO_BACKUP_IMAGE_WALLPAPER_REQUEST_CODE);
- }
-
private void finishWithResultOk(boolean shouldShowMessage) {
if (shouldShowMessage) {
try {
diff --git a/src/com/android/wallpaper/picker/individual/IndividualPickerFragment.java b/src/com/android/wallpaper/picker/individual/IndividualPickerFragment.java
index db21da3..c0c4ce5 100755
--- a/src/com/android/wallpaper/picker/individual/IndividualPickerFragment.java
+++ b/src/com/android/wallpaper/picker/individual/IndividualPickerFragment.java
@@ -58,13 +58,11 @@ import com.android.wallpaper.model.WallpaperRotationInitializer;
import com.android.wallpaper.model.WallpaperRotationInitializer.Listener;
import com.android.wallpaper.model.WallpaperRotationInitializer.NetworkPreference;
import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
-import com.android.wallpaper.model.WallpaperRotationInitializer.RotationStateListener;
import com.android.wallpaper.module.FormFactorChecker;
import com.android.wallpaper.module.FormFactorChecker.FormFactor;
import com.android.wallpaper.module.Injector;
import com.android.wallpaper.module.InjectorProvider;
import com.android.wallpaper.module.PackageStatusNotifier;
-import com.android.wallpaper.module.RotatingWallpaperComponentChecker;
import com.android.wallpaper.module.WallpaperChangedNotifier;
import com.android.wallpaper.module.WallpaperPersister;
import com.android.wallpaper.module.WallpaperPersister.Destination;
@@ -116,7 +114,6 @@ public class IndividualPickerFragment extends Fragment
WallpaperPreferences mWallpaperPreferences;
WallpaperChangedNotifier mWallpaperChangedNotifier;
- RotatingWallpaperComponentChecker mRotatingWallpaperComponentChecker;
RecyclerView mImageGrid;
IndividualAdapter mAdapter;
WallpaperCategory mCategory;
@@ -250,8 +247,6 @@ public class IndividualPickerFragment extends Fragment
mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
mWallpaperChangedNotifier.registerListener(mWallpaperChangedListener);
- mRotatingWallpaperComponentChecker = injector.getRotatingWallpaperComponentChecker();
-
mFormFactor = injector.getFormFactorChecker(appContext).getFormFactor();
mPackageStatusNotifier = injector.getPackageStatusNotifier(appContext);
@@ -445,7 +440,8 @@ public class IndividualPickerFragment extends Fragment
public void onResume() {
super.onResume();
- WallpaperPreferences preferences = InjectorProvider.getInjector().getPreferences(getActivity());
+ WallpaperPreferences preferences = InjectorProvider.getInjector()
+ .getPreferences(getActivity());
preferences.setLastAppActiveTimestamp(new Date().getTime());
// Reset Glide memory settings to a "normal" level of usage since it may have been lowered in
@@ -541,31 +537,23 @@ public class IndividualPickerFragment extends Fragment
* state of the user's device and binds the state of the current category's rotation to the "start
* rotation" tile.
*/
- private void refreshRotationHolder(final RotationHolder rotationHolder) {
+ private void refreshRotationHolder(RotationHolder rotationHolder) {
mWallpaperRotationInitializer.fetchRotationInitializationState(getContext(),
- new RotationStateListener() {
- @Override
- public void onRotationStateReceived(
- @RotationInitializationState final int rotationInitializationState) {
-
- // Update the UI state of the "start rotation" tile displayed on screen. Do this in a
- // Handler so it is scheduled at the end of the message queue. This is necessary to
- // ensure we do not remove or add data from the adapter while the layout is still being
- // computed. RecyclerView documentation therefore recommends performing such changes in
- // a Handler.
- new android.os.Handler().post(new Runnable() {
- @Override
- public void run() {
- // A config change may have destroyed the activity since the refresh started, so
- // check for that to avoid an NPE.
- if (getActivity() == null) {
- return;
- }
+ rotationState -> {
+ // Update the UI state of the "start rotation" tile displayed on screen.
+ // Do this in a Handler so it is scheduled at the end of the message queue.
+ // This is necessary to ensure we do not remove or add data from the adapter
+ // while the layout is still being computed. RecyclerView documentation
+ // therefore recommends performing such changes in a Handler.
+ new Handler().post(() -> {
+ // A config change may have destroyed the activity since the refresh
+ // started, so check for that to avoid an NPE.
+ if (getActivity() == null) {
+ return;
+ }
- rotationHolder.bindRotationInitializationState(rotationInitializationState);
- }
- });
- }
+ rotationHolder.bindRotationInitializationState(rotationState);
+ });
});
}
@@ -614,34 +602,33 @@ public class IndividualPickerFragment extends Fragment
// app before the first wallpaper image in rotation finishes downloading.
Activity activity = getActivity();
- if (activity != null
- && mWallpaperRotationInitializer
- .isNoBackupImageWallpaperPreviewNeeded(appContext)) {
- ((IndividualPickerActivity) activity).showNoBackupImageWallpaperPreview();
- } else {
- if (mWallpaperRotationInitializer.startRotation(appContext)) {
- if (activity != null && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
- try {
- Toast.makeText(getActivity(), R.string.wallpaper_set_successfully_message,
- Toast.LENGTH_SHORT).show();
- } catch (NotFoundException e) {
- Log.e(TAG, "Could not show toast " + e);
- }
- activity.setResult(Activity.RESULT_OK);
- activity.finish();
- } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
- mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
- }
- } else { // Failed to start rotation.
- showStartRotationErrorDialog(networkPreference);
-
- if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
- DesktopRotationHolder rotationViewHolder =
- (DesktopRotationHolder) mImageGrid.findViewHolderForAdapterPosition(
- SPECIAL_FIXED_TILE_ADAPTER_POSITION);
- rotationViewHolder.setSelectionState(SelectableHolder.SELECTION_STATE_DESELECTED);
+ if (mWallpaperRotationInitializer.startRotation(appContext)) {
+ if (activity != null
+ && mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+ try {
+ Toast.makeText(getActivity(),
+ R.string.wallpaper_set_successfully_message,
+ Toast.LENGTH_SHORT).show();
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Could not show toast " + e);
}
+
+ activity.setResult(Activity.RESULT_OK);
+ activity.finish();
+ } else if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
+ mAdapter.updateSelectedTile(SPECIAL_FIXED_TILE_ADAPTER_POSITION);
+ }
+ } else { // Failed to start rotation.
+ showStartRotationErrorDialog(networkPreference);
+
+ if (mFormFactor == FormFactorChecker.FORM_FACTOR_DESKTOP) {
+ DesktopRotationHolder rotationViewHolder =
+ (DesktopRotationHolder)
+ mImageGrid.findViewHolderForAdapterPosition(
+ SPECIAL_FIXED_TILE_ADAPTER_POSITION);
+ rotationViewHolder.setSelectionState(
+ SelectableHolder.SELECTION_STATE_DESELECTED);
}
}
}
@@ -690,11 +677,7 @@ public class IndividualPickerFragment extends Fragment
* Returns whether rotation is enabled for this category.
*/
boolean isRotationEnabled() {
- boolean isRotationSupported =
- mRotatingWallpaperComponentChecker.getRotatingWallpaperSupport(getContext())
- == RotatingWallpaperComponentChecker.ROTATING_WALLPAPER_SUPPORT_SUPPORTED;
-
- return isRotationSupported && mWallpaperRotationInitializer != null;
+ return mWallpaperRotationInitializer != null;
}
@Override
@@ -732,10 +715,10 @@ public class IndividualPickerFragment extends Fragment
super(itemView);
itemView.setOnClickListener(this);
- mTileLayout = (FrameLayout) itemView.findViewById(R.id.daily_refresh);
- mRotationMessage = (TextView) itemView.findViewById(R.id.rotation_tile_message);
- mRotationTitle = (TextView) itemView.findViewById(R.id.rotation_tile_title);
- mRefreshIcon = (ImageView) itemView.findViewById(R.id.rotation_tile_refresh_icon);
+ mTileLayout = itemView.findViewById(R.id.daily_refresh);
+ mRotationMessage = itemView.findViewById(R.id.rotation_tile_message);
+ mRotationTitle = itemView.findViewById(R.id.rotation_tile_title);
+ mRefreshIcon = itemView.findViewById(R.id.rotation_tile_refresh_icon);
mTileLayout.getLayoutParams().height = mTileSizePx.y;
// If the feature flag for "dynamic start rotation tile" is not enabled, fall back to the
@@ -749,7 +732,8 @@ public class IndividualPickerFragment extends Fragment
mRotationMessage.setTextColor(
getResources().getColor(R.color.rotation_tile_enabled_subtitle_text_color));
mRefreshIcon.setColorFilter(
- getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color), Mode.SRC_IN);
+ getResources().getColor(R.color.rotation_tile_enabled_refresh_icon_color),
+ Mode.SRC_IN);
return;
}
@@ -765,10 +749,7 @@ public class IndividualPickerFragment extends Fragment
@Override
public void onClick(View v) {
- boolean isLiveWallpaperNeeded = mWallpaperRotationInitializer
- .isNoBackupImageWallpaperPreviewNeeded(getActivity().getApplicationContext());
- DialogFragment startRotationDialogFragment = StartRotationDialogFragment
- .newInstance(isLiveWallpaperNeeded);
+ DialogFragment startRotationDialogFragment = new StartRotationDialogFragment();
startRotationDialogFragment.setTargetFragment(
IndividualPickerFragment.this, UNUSED_REQUEST_CODE);
startRotationDialogFragment.show(getFragmentManager(), TAG_START_ROTATION_DIALOG);
diff --git a/src/com/android/wallpaper/widget/ConstraintViewPager.java b/src/com/android/wallpaper/widget/ConstraintViewPager.java
new file mode 100644
index 0000000..ad56750
--- /dev/null
+++ b/src/com/android/wallpaper/widget/ConstraintViewPager.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wallpaper.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.viewpager.widget.ViewPager;
+
+/**
+ * When ConstraintViewPager is being measured, it will get all height of pages and makes itself
+ * height as the same as the maximum height.
+ */
+public class ConstraintViewPager extends ViewPager {
+
+ public ConstraintViewPager(@NonNull Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public ConstraintViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Visit all child views first and then determine the maximum height for ViewPager.
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int maxChildHeight = 0;
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ view.measure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(0 /* size */, MeasureSpec.UNSPECIFIED));
+ int childHeight = view.getMeasuredHeight();
+ if (childHeight > maxChildHeight) {
+ maxChildHeight = childHeight;
+ }
+ }
+
+ if (maxChildHeight != 0) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/src_override/com/android/wallpaper/module/WallpapersInjector.java b/src_override/com/android/wallpaper/module/WallpapersInjector.java
index 8e3b3e9..5a39524 100755
--- a/src_override/com/android/wallpaper/module/WallpapersInjector.java
+++ b/src_override/com/android/wallpaper/module/WallpapersInjector.java
@@ -17,12 +17,12 @@ package com.android.wallpaper.module;
import android.content.Context;
+import androidx.fragment.app.Fragment;
+
import com.android.wallpaper.model.CategoryProvider;
import com.android.wallpaper.model.WallpaperInfo;
import com.android.wallpaper.monitor.PerformanceMonitor;
-import com.android.wallpaper.picker.PreviewFragment;
-
-import androidx.fragment.app.Fragment;
+import com.android.wallpaper.picker.ImagePreviewFragment;
/**
* A concrete, real implementation of the dependency provider.
@@ -69,7 +69,7 @@ public class WallpapersInjector extends BaseWallpaperInjector {
WallpaperInfo wallpaperInfo,
int mode,
boolean testingModeEnabled) {
- return PreviewFragment.newInstance(wallpaperInfo, mode, testingModeEnabled);
+ return ImagePreviewFragment.newInstance(wallpaperInfo, mode, testingModeEnabled);
}
@Override
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..be224e3
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,59 @@
+# Copyright (C) 2019 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+#
+# Build rule for WallpaperPicker2 tests
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx.annotation_annotation \
+ androidx.test.core \
+ androidx.test.runner \
+ androidx.test.rules \
+ androidx.test.espresso.contrib \
+ androidx.test.espresso.intents \
+ mockito-target-minus-junit4 \
+ androidx.test.espresso.core \
+ hamcrest-library \
+ hamcrest
+
+ifneq (,$(wildcard frameworks/base))
+ LOCAL_PRIVATE_PLATFORM_APIS := true
+else
+ LOCAL_SDK_VERSION := 29
+ LOCAL_MIN_SDK_VERSION := 26
+endif
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_ANDROID_LIBRARIES := WallpaperPicker2CommonDepsLib
+
+LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := AndroidManifest.xml
+
+LOCAL_INSTRUMENTATION_FOR := WallpaperPicker2
+
+LOCAL_PACKAGE_NAME := WallpaperPicker2Tests
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
new file mode 100644
index 0000000..1e35c92
--- /dev/null
+++ b/tests/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.wallpaper.tests">
+
+ <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="29"/>
+
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation
+ android:functionalTest="false"
+ android:handleProfiling="false"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wallpaper">
+ </instrumentation>
+</manifest>
diff --git a/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java b/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java
new file mode 100644
index 0000000..e1feba5
--- /dev/null
+++ b/tests/src/com/android/wallpaper/picker/PreviewActivityTest.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2019 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 static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static junit.framework.TestCase.assertFalse;
+
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+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 android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.widget.TextView;
+
+import androidx.test.espresso.intent.Intents;
+import androidx.test.filters.MediumTest;
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.UserEventLogger;
+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.TestUserEventLogger;
+import com.android.wallpaper.testing.TestWallpaperInfo;
+import com.android.wallpaper.testing.TestWallpaperPersister;
+import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.WallpaperCropUtils;
+
+import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link PreviewActivity}.
+ */
+@RunWith(AndroidJUnit4ClassRunner.class)
+@MediumTest
+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 Injector mInjector;
+ private TestWallpaperPersister mWallpaperPersister;
+ private TestUserEventLogger mEventLogger;
+ private TestExploreIntentChecker mExploreIntentChecker;
+
+ @Rule
+ public ActivityTestRule<PreviewActivity> mActivityRule =
+ new ActivityTestRule<>(PreviewActivity.class, false, false);
+
+ @Before
+ public void setUp() {
+
+ mInjector = new TestInjector();
+ InjectorProvider.setInjector(mInjector);
+
+ Intents.init();
+
+ mMockWallpaper = new TestWallpaperInfo(TestWallpaperInfo.COLOR_BLACK);
+ 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);
+
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mWallpaperPersister = (TestWallpaperPersister) mInjector.getWallpaperPersister(context);
+ mEventLogger = (TestUserEventLogger) mInjector.getUserEventLogger(context);
+ mExploreIntentChecker = (TestExploreIntentChecker)
+ mInjector.getExploreIntentChecker(context);
+ }
+
+ @After
+ public void tearDown() {
+ Intents.release();
+ mActivityRule.finishActivity();
+ }
+
+ private void launchActivityIntentWithMockWallpaper() {
+ Intent intent = PreviewActivity.newIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), mMockWallpaper);
+ intent.putExtra(BasePreviewActivity.EXTRA_TESTING_MODE_ENABLED, true);
+
+ mActivityRule.launchActivity(intent);
+ }
+
+ private void finishSettingWallpaper() throws Throwable {
+ mActivityRule.runOnUiThread(() -> mWallpaperPersister.finishSettingWallpaper());
+ }
+
+ @Test
+ public void testRendersWallpaperDrawableFromIntent() {
+ launchActivityIntentWithMockWallpaper();
+ PreviewActivity activity = mActivityRule.getActivity();
+ SubsamplingScaleImageView mosaicView = activity.findViewById(R.id.full_res_image);
+
+ assertTrue(mosaicView.hasImage());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Success_HomeScreen() throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Home screen".
+ onView(withText(R.string.set_wallpaper_home_screen_destination)).perform(click());
+
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+
+ finishSettingWallpaper();
+
+ // 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();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper()));
+
+ // The wallpaper should have been set on the home screen.
+ assertEquals(WallpaperPersister.DEST_HOME_SCREEN, mWallpaperPersister.getLastDestination());
+ assertEquals(1, mEventLogger.getNumWallpaperSetEvents());
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS,
+ mEventLogger.getLastWallpaperSetResult());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Success_LockScreen() throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Lock screen."
+ onView(withText(R.string.set_wallpaper_lock_screen_destination)).perform(click());
+
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ finishSettingWallpaper();
+
+ // 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();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper()));
+
+ // The wallpaper should have been set on the lock screen.
+ assertEquals(WallpaperPersister.DEST_LOCK_SCREEN, mWallpaperPersister.getLastDestination());
+ assertEquals(1, mEventLogger.getNumWallpaperSetEvents());
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS,
+ mEventLogger.getLastWallpaperSetResult());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Success_BothHomeAndLockScreen() throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Both."
+ onView(withText(R.string.set_wallpaper_both_destination)).perform(click());
+
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ finishSettingWallpaper();
+
+ // 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();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper()));
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper()));
+
+ // The wallpaper should have been set on both the home and the lock screen.
+ assertEquals(WallpaperPersister.DEST_BOTH, mWallpaperPersister.getLastDestination());
+ assertEquals(1, mEventLogger.getNumWallpaperSetEvents());
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_SUCCESS,
+ mEventLogger.getLastWallpaperSetResult());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Fails_HomeScreen_ShowsErrorDialog()
+ throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+
+ mWallpaperPersister.setFailNextCall(true);
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Home screen."
+ onView(withText(R.string.set_wallpaper_home_screen_destination)).perform(click());
+
+ finishSettingWallpaper();
+
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ onView(withText(R.string.set_wallpaper_error_message)).check(matches(isDisplayed()));
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_FAILURE,
+ mEventLogger.getLastWallpaperSetResult());
+
+ // Set next call to succeed and current wallpaper bitmap should not be null and equals to
+ // the
+ // mock wallpaper bitmap after clicking "try again".
+ mWallpaperPersister.setFailNextCall(false);
+
+ onView(withText(R.string.try_again)).perform(click());
+ finishSettingWallpaper();
+
+ assertNotNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper()));
+
+ // The wallpaper should have been set on the home screen.
+ assertEquals(WallpaperPersister.DEST_HOME_SCREEN, mWallpaperPersister.getLastDestination());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Fails_LockScreen_ShowsErrorDialog()
+ throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ mWallpaperPersister.setFailNextCall(true);
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Lock screen."
+ onView(withText(R.string.set_wallpaper_lock_screen_destination)).perform(click());
+
+ finishSettingWallpaper();
+
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+ onView(withText(R.string.set_wallpaper_error_message)).check(matches(isDisplayed()));
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_FAILURE,
+ mEventLogger.getLastWallpaperSetResult());
+
+ // Set next call to succeed and current wallpaper bitmap should not be null and equals to
+ // the
+ // mock wallpaper bitmap after clicking "try again".
+ mWallpaperPersister.setFailNextCall(false);
+
+ onView(withText(R.string.try_again)).perform(click());
+ finishSettingWallpaper();
+
+ assertNotNull(mWallpaperPersister.getCurrentLockWallpaper());
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper()));
+
+ // The wallpaper should have been set on the lock screen.
+ assertEquals(WallpaperPersister.DEST_LOCK_SCREEN, mWallpaperPersister.getLastDestination());
+ }
+
+ @Test
+ public void testClickSetWallpaper_Fails_BothHomeAndLock_ShowsErrorDialog()
+ throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+
+ mWallpaperPersister.setFailNextCall(true);
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Both."
+ onView(withText(R.string.set_wallpaper_both_destination)).perform(click());
+
+ finishSettingWallpaper();
+
+ assertNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ assertNull(mWallpaperPersister.getCurrentLockWallpaper());
+ onView(withText(R.string.set_wallpaper_error_message)).check(matches(isDisplayed()));
+
+ assertEquals(1, mEventLogger.getNumWallpaperSetResultEvents());
+ assertEquals(UserEventLogger.WALLPAPER_SET_RESULT_FAILURE,
+ mEventLogger.getLastWallpaperSetResult());
+
+ // Set next call to succeed and current wallpaper bitmap should not be null and equals to
+ // the mock wallpaper bitmap after clicking "try again".
+ mWallpaperPersister.setFailNextCall(false);
+
+ onView(withText(R.string.try_again)).perform(click());
+ finishSettingWallpaper();
+
+ assertNotNull(mWallpaperPersister.getCurrentHomeWallpaper());
+ assertNotNull(mWallpaperPersister.getCurrentLockWallpaper());
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ Bitmap srcBitmap = ((TestAsset) mMockWallpaper.getAsset(context)).getBitmap();
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentHomeWallpaper()));
+ assertTrue(srcBitmap.sameAs(mWallpaperPersister.getCurrentLockWallpaper()));
+
+ // The wallpaper should have been set on both the home screen and the lock screen.
+ assertEquals(WallpaperPersister.DEST_BOTH, mWallpaperPersister.getLastDestination());
+ }
+
+ @Test
+ public void testClickSetWallpaper_CropsAndScalesWallpaper() {
+ launchActivityIntentWithMockWallpaper();
+ // Scale should not have a meaningful value before clicking "set wallpaper".
+ assertTrue(mWallpaperPersister.getScale() < 0);
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Home screen".
+ onView(withText(R.string.set_wallpaper_home_screen_destination)).perform(click());
+
+ // WallpaperPersister's scale should match the ScaleImageView's scale.
+ float zoom = ((SubsamplingScaleImageView)
+ mActivityRule.getActivity().findViewById(R.id.full_res_image)).getScale();
+ assertEquals(mWallpaperPersister.getScale(), zoom, FLOAT_ERROR_MARGIN);
+
+ Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+ mActivityRule.getActivity().getWindowManager().getDefaultDisplay());
+ int maxDim = Math.max(screenSize.x, screenSize.y);
+ Rect cropRect = mWallpaperPersister.getCropRect();
+
+ // Crop rect should be greater or equal than screen size in both directions.
+ assertTrue(cropRect.width() >= maxDim);
+ assertTrue(cropRect.height() >= maxDim);
+ }
+
+ @Test
+ public void testClickSetWallpaper_FailsCroppingAndScalingWallpaper_ShowsErrorDialog()
+ throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ mWallpaperPersister.setFailNextCall(true);
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+ // Destination dialog is shown; click "Home screen".
+ onView(withText(R.string.set_wallpaper_home_screen_destination)).perform(click());
+
+ finishSettingWallpaper();
+
+ onView(withText(R.string.set_wallpaper_error_message)).check(matches(isDisplayed()));
+ }
+
+ /**
+ * Tests that tapping Set Wallpaper shows the destination dialog (i.e., choosing
+ * between Home screen, Lock screen, or Both).
+ */
+ @Test
+ public void testClickSetWallpaper_ShowsDestinationDialog() {
+ launchActivityIntentWithMockWallpaper();
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+ onView(withText(R.string.set_wallpaper_dialog_message)).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSetsDefaultWallpaperZoomAndScroll() {
+ float expectedWallpaperZoom;
+ int expectedWallpaperScrollX;
+ int expectedWallpaperScrollY;
+
+ launchActivityIntentWithMockWallpaper();
+ PreviewActivity activity = mActivityRule.getActivity();
+ SubsamplingScaleImageView fullResImageView = activity.findViewById(R.id.full_res_image);
+
+ Point defaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
+ activity.getResources(), activity.getWindowManager().getDefaultDisplay());
+ Point screenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+ activity.getWindowManager().getDefaultDisplay());
+ TestAsset asset = (TestAsset) mMockWallpaper.getAsset(activity);
+ Point wallpaperSize = new Point(asset.getBitmap().getWidth(),
+ asset.getBitmap().getHeight());
+
+ expectedWallpaperZoom = WallpaperCropUtils.calculateMinZoom(
+ wallpaperSize, defaultCropSurfaceSize);
+
+ // Current zoom should match the minimum zoom required to fit wallpaper
+ // completely on the crop surface.
+ assertEquals(expectedWallpaperZoom, fullResImageView.getScale(), FLOAT_ERROR_MARGIN);
+
+ Point scaledWallpaperSize = new Point(
+ (int) (wallpaperSize.x * expectedWallpaperZoom),
+ (int) (wallpaperSize.y * expectedWallpaperZoom));
+ Point cropSurfaceToScreen = WallpaperCropUtils.calculateCenterPosition(
+ defaultCropSurfaceSize, screenSize, true /* alignStart */, false /* isRtl */);
+ Point wallpaperToCropSurface = WallpaperCropUtils.calculateCenterPosition(
+ scaledWallpaperSize, defaultCropSurfaceSize, false /* alignStart */,
+ false /* isRtl */);
+
+ expectedWallpaperScrollX = wallpaperToCropSurface.x + cropSurfaceToScreen.x;
+ expectedWallpaperScrollY = wallpaperToCropSurface.y + cropSurfaceToScreen.y;
+
+ // ZoomView should be scrolled in X and Y directions such that the crop surface is centered
+ // relative to the wallpaper and the screen is centered (and aligned left) relative to the
+ // crop surface.
+ assertEquals(expectedWallpaperScrollX, fullResImageView.getScrollX());
+ assertEquals(expectedWallpaperScrollY, fullResImageView.getScrollY());
+ }
+
+ @Test
+ public void testSetWallpaper_TemporarilyLocksScreenOrientation() throws Throwable {
+ launchActivityIntentWithMockWallpaper();
+ PreviewActivity activity = mActivityRule.getActivity();
+
+ assertFalse(activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+
+ onView(withId(R.id.preview_attribution_pane_set_wallpaper_button)).perform(click());
+
+ // Destination dialog is shown; click "Home screen".
+ onView(withText(R.string.set_wallpaper_home_screen_destination)).perform(click());
+
+ assertEquals(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activity.getRequestedOrientation());
+
+ // Finish setting the wallpaper to check that the screen orientation is no longer locked.
+ finishSettingWallpaper();
+
+ assertNotEquals(activity.getRequestedOrientation(), ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+ }
+ @Test
+ public void testShowsWallpaperAttribution() {
+ launchActivityIntentWithMockWallpaper();
+ PreviewActivity activity = mActivityRule.getActivity();
+
+ TextView titleView = activity.findViewById(R.id.preview_attribution_pane_title);
+ assertEquals("Title", titleView.getText());
+
+ TextView subtitle1View = activity.findViewById(R.id.preview_attribution_pane_subtitle1);
+ assertEquals("Subtitle 1", subtitle1View.getText());
+
+ TextView subtitle2View = activity.findViewById(R.id.preview_attribution_pane_subtitle2);
+ assertEquals("Subtitle 2", subtitle2View.getText());
+ }
+
+ /**
+ * Tests that if there was a failure decoding the wallpaper bitmap, then the activity shows an
+ * informative error dialog with an "OK" button, when clicked finishes the activity.
+ */
+ @Test
+ public void testLoadWallpaper_Failed_ShowsErrorDialog() {
+ // Simulate a corrupted asset that fails to perform decoding operations.
+ mMockWallpaper.corruptAssets();
+ launchActivityIntentWithMockWallpaper();
+
+ onView(withText(R.string.load_wallpaper_error_message)).check(matches(isDisplayed()));
+
+ onView(withText(android.R.string.ok)).perform(click());
+
+ assertTrue(mActivityRule.getActivity().isFinishing());
+ }
+
+ /**
+ * Tests that the explore button is not visible, even if there is an action URL present, if
+ * there is no activity on the device which can handle such an explore action.
+ */
+ @Test
+ public void testNoActionViewHandler_ExploreButtonNotVisible() {
+ mExploreIntentChecker.setViewHandlerExists(false);
+
+ launchActivityIntentWithMockWallpaper();
+ onView(withId(R.id.preview_attribution_pane_explore_button)).check(
+ matches(not(isDisplayed())));
+ }
+}
diff --git a/tests/src/com/android/wallpaper/picker/individual/IndividualPickerActivityTest.java b/tests/src/com/android/wallpaper/picker/individual/IndividualPickerActivityTest.java
new file mode 100644
index 0000000..d91c16a
--- /dev/null
+++ b/tests/src/com/android/wallpaper/picker/individual/IndividualPickerActivityTest.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2019 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.individual;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.intent.Intents.intended;
+import static androidx.test.espresso.intent.Intents.intending;
+import static androidx.test.espresso.intent.matcher.ComponentNameMatchers.hasClassName;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+import static androidx.test.espresso.matcher.ViewMatchers.isChecked;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static junit.framework.TestCase.assertFalse;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation.ActivityResult;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.ColorDrawable;
+import android.widget.FrameLayout;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.espresso.contrib.RecyclerViewActions;
+import androidx.test.espresso.intent.Intents;
+import androidx.test.filters.MediumTest;
+import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.config.Flags;
+import com.android.wallpaper.model.Category;
+import com.android.wallpaper.model.PickerIntentFactory;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.model.WallpaperRotationInitializer;
+import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
+import com.android.wallpaper.module.FormFactorChecker;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.testing.TestCategoryProvider;
+import com.android.wallpaper.testing.TestFormFactorChecker;
+import com.android.wallpaper.testing.TestInjector;
+import com.android.wallpaper.testing.TestUserEventLogger;
+import com.android.wallpaper.testing.TestWallpaperCategory;
+import com.android.wallpaper.testing.TestWallpaperInfo;
+import com.android.wallpaper.testing.TestWallpaperRotationInitializer;
+
+import org.hamcrest.Matcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link IndividualPickerActivity}.
+ */
+@RunWith(AndroidJUnit4ClassRunner.class)
+@MediumTest
+public class IndividualPickerActivityTest {
+
+ private static final String EXTRA_WALLPAPER_INFO =
+ "com.android.wallpaper.picker.wallpaper_info";
+ private static final TestWallpaperInfo sWallpaperInfo1 = new TestWallpaperInfo(
+ TestWallpaperInfo.COLOR_BLACK, "test-wallpaper-1");
+ private static final TestWallpaperInfo sWallpaperInfo2 = new TestWallpaperInfo(
+ TestWallpaperInfo.COLOR_BLACK, "test-wallpaper-2");
+ private static final TestWallpaperInfo sWallpaperInfo3 = new TestWallpaperInfo(
+ TestWallpaperInfo.COLOR_BLACK, "test-wallpaper-3");
+
+ private TestCategoryProvider mTestCategoryProvider;
+
+ private TestFormFactorChecker mTestFormFactorChecker;
+ private Injector mInjector;
+
+ private TestWallpaperCategory mTestCategory;
+
+ @Rule
+ public ActivityTestRule<IndividualPickerActivity> mActivityRule =
+ new ActivityTestRule<>(IndividualPickerActivity.class, false, false);
+
+ @Before
+ public void setUp() {
+ Intents.init();
+
+ mInjector = new TestInjector();
+ InjectorProvider.setInjector(mInjector);
+
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mTestFormFactorChecker = (TestFormFactorChecker) mInjector.getFormFactorChecker(context);
+ mTestCategoryProvider = (TestCategoryProvider) mInjector.getCategoryProvider(context);
+
+ sWallpaperInfo1.setAttributions(Arrays.asList(
+ "Attribution 0", "Attribution 1", "Attribution 2"));
+ }
+
+ @After
+ public void tearDown() {
+ Intents.release();
+ mActivityRule.finishActivity();
+ }
+
+ private IndividualPickerActivity getActivity() {
+ return mActivityRule.getActivity();
+ }
+
+ private void setUpFragmentForTesting() {
+ IndividualPickerFragment fragment = (IndividualPickerFragment)
+ getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_container);
+ fragment.setTestingMode(true);
+ }
+
+ private void setActivityWithMockWallpapers(boolean isRotationEnabled,
+ @RotationInitializationState int rotationState) {
+ sWallpaperInfo1.setCollectionId("collection");
+
+ ArrayList<WallpaperInfo> wallpapers = new ArrayList<>();
+ wallpapers.add(sWallpaperInfo1);
+ wallpapers.add(sWallpaperInfo2);
+ wallpapers.add(sWallpaperInfo3);
+
+ mTestCategory = new TestWallpaperCategory(
+ "Test category", "collection", wallpapers, 0 /* priority */);
+ mTestCategory.setIsRotationEnabled(isRotationEnabled);
+ mTestCategory.setRotationInitializationState(rotationState);
+
+ List<Category> testCategories = mTestCategoryProvider.getTestCategories();
+ testCategories.set(0, mTestCategory);
+
+ PickerIntentFactory intentFactory =
+ new IndividualPickerActivity.IndividualPickerActivityIntentFactory();
+ Intent intent = intentFactory.newIntent(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(),
+ mTestCategory.getCollectionId());
+ mActivityRule.launchActivity(intent);
+ }
+
+ @Test
+ public void testDrawsTilesForProvidedWallpapers() {
+ setActivityWithMockWallpapers(false /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ IndividualPickerActivity activity = getActivity();
+
+ RecyclerView recyclerView = activity.findViewById(R.id.wallpaper_grid);
+
+ // There are only three wallpapers in the category, so the grid should only have three
+ // items.
+ assertNotNull(recyclerView.findViewHolderForAdapterPosition(0));
+ assertNotNull(recyclerView.findViewHolderForAdapterPosition(1));
+ assertNotNull(recyclerView.findViewHolderForAdapterPosition(2));
+ assertNull(recyclerView.findViewHolderForAdapterPosition(3));
+ }
+
+ @Test
+ public void testClickTile_Mobile_LaunchesPreviewActivityWithWallpaper() {
+ mTestFormFactorChecker.setFormFactor(FormFactorChecker.FORM_FACTOR_MOBILE);
+
+ setActivityWithMockWallpapers(false /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ onView(withId(R.id.wallpaper_grid)).perform(
+ RecyclerViewActions.actionOnItemAtPosition(0, click()));
+ intended(allOf(
+ hasComponent(hasClassName("com.android.wallpaper.picker.PreviewActivity")),
+ hasExtra(equalTo(EXTRA_WALLPAPER_INFO), equalTo(sWallpaperInfo1))));
+
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ TestUserEventLogger eventLogger = (TestUserEventLogger) mInjector.getUserEventLogger(
+ context);
+ assertEquals(1, eventLogger.getNumIndividualWallpaperSelectedEvents());
+ assertEquals(sWallpaperInfo1.getCollectionId(context), eventLogger.getLastCollectionId());
+ }
+
+ /**
+ * Tests that the static daily rotation tile (with flag dynamicStartRotationTileEnabled=false)
+ * has a background of the light blue accent color and says "Tap to turn on".
+ */
+ @Test
+ public void testRotationEnabled_StaticDailyRotationTile() {
+ Flags.dynamicStartRotationTileEnabled = false;
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(matches(isDisplayed()));
+ onView(withText(R.string.daily_refresh_tile_subtitle)).check(matches(isDisplayed()));
+
+ // Check that the background color of the "daily refresh" tile is the blue accent color.
+ FrameLayout rotationTile = getActivity().findViewById(R.id.daily_refresh);
+ int backgroundColor = ((ColorDrawable) rotationTile.getBackground()).getColor();
+ assertEquals(getActivity().getResources().getColor(R.color.accent_color),
+ backgroundColor);
+ }
+
+ /**
+ * Tests that when rotation is enabled and the rotation for this category is already in effect
+ * on both home & lock screens, then the "start rotation" tile reads "Home & Lock".
+ */
+ @Test
+ public void testRotationEnabled_RotationInitializedHomeAndLock() {
+ Flags.dynamicStartRotationTileEnabled = true;
+
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_HOME_AND_LOCK);
+ getActivity();
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(matches(isDisplayed()));
+ onView(withText(R.string.home_and_lock_short_label)).check(matches(isDisplayed()));
+ }
+
+ /**
+ * Tests that when rotation is enabled and the rotation is aleady for this category is already
+ * in
+ * effect on the home-screen only, then the "start rotation" tile reads "Home screen".
+ */
+ @Test
+ public void testRotationEnabled_RotationInitializedHomeScreenOnly() {
+ Flags.dynamicStartRotationTileEnabled = true;
+
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_HOME_ONLY);
+ getActivity();
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(matches(isDisplayed()));
+ onView(withText(R.string.home_screen_message)).check(matches(isDisplayed()));
+ }
+
+ /**
+ * Tests that after the IndividualPickerActivity loads, if the state of the current category's
+ * rotation changes while the activity is restarted, then the UI for the "start rotation" tile
+ * changes to reflect that new state.
+ */
+ @Test
+ public void testActivityRestarted_RotationStateChanges_StartRotationTileUpdates()
+ throws Throwable {
+ Flags.dynamicStartRotationTileEnabled = true;
+
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_HOME_ONLY);
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(matches(isDisplayed()));
+ onView(withText(R.string.home_screen_message)).check(matches(isDisplayed()));
+
+ // Now change the rotation initialization state such that the tile should say
+ // "Tap to turn on" after the activity resumes.
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ testWPRotationInitializer.setRotationInitializationState(
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+
+ // Restart the activity.
+ IndividualPickerActivity activity = getActivity();
+ mActivityRule.runOnUiThread(activity::recreate);
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(matches(isDisplayed()));
+ onView(withText(R.string.daily_refresh_tile_subtitle)).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testRotationDisabled_DoesNotRenderDailyRefreshTile() {
+ setActivityWithMockWallpapers(false /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ onView(withText(R.string.daily_refresh_tile_title)).check(doesNotExist());
+ onView(withText(R.string.daily_refresh_tile_subtitle)).check(doesNotExist());
+ }
+
+ @Test
+ public void testClickDailyRefreshTile_ShowsStartRotationDialog() {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+
+ onView(withId(R.id.start_rotation_wifi_only_checkbox))
+ .check(matches(isDisplayed()));
+ // WiFi-only option should be checked by default.
+ onView(withId(R.id.start_rotation_wifi_only_checkbox))
+ .check(matches(isChecked()));
+ }
+
+ @Test
+ public void testShowStartRotationDialog_WifiOnly_ClickOK_StartsRotation() throws Throwable {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ // Mock out the intent and response for the live wallpaper preview.
+ Matcher<Intent> expectedIntent = hasAction(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
+ intending(expectedIntent).respondWith(new ActivityResult(Activity.RESULT_OK, null));
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+
+ onView(withText(android.R.string.ok)).perform(click());
+ mActivityRule.runOnUiThread(() -> {
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(true /* isSuccessful */);
+ assertTrue(testWPRotationInitializer.isRotationInitialized());
+ assertTrue(testWPRotationInitializer.isWifiOnly());
+
+ // The activity should finish if starting a rotation was successful.
+ assertTrue(getActivity().isFinishing());
+ });
+ }
+
+ @Test
+ public void testShowStartRotationDialog_WifiOnly_ClickOK_Fails_ShowsErrorDialog() {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+ onView(withText(android.R.string.ok)).perform(click());
+
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(false /* isSuccessful */);
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ // Error dialog should be shown with retry option.
+ onView(withText(R.string.start_rotation_error_message)).check(matches(isDisplayed()));
+ onView(withText(R.string.try_again)).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testStartRotation_WifiOnly_FailOnce_Retry() throws Throwable {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+ onView(withText(android.R.string.ok)).perform(click());
+
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(false /* isSuccessful */);
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ // Click try again to retry.
+ onView(withText(R.string.try_again)).perform(click());
+
+ mActivityRule.runOnUiThread(() -> {
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(true /* isSuccessful */);
+ assertTrue(testWPRotationInitializer.isRotationInitialized());
+ assertTrue(testWPRotationInitializer.isWifiOnly());
+ });
+ }
+
+ @Test
+ public void testShowStartRotationDialog_TurnOffWifiOnly_ClickOK_StartsRotation()
+ throws Throwable {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+ // Click on WiFi-only option to toggle it off.
+ onView(withId(R.id.start_rotation_wifi_only_checkbox)).perform(click());
+ onView(withText(android.R.string.ok)).perform(click());
+
+ mActivityRule.runOnUiThread(() -> {
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(true /* isSuccessful */);
+ assertTrue(testWPRotationInitializer.isRotationInitialized());
+ assertFalse(testWPRotationInitializer.isWifiOnly());
+ });
+ }
+
+ @Test
+ public void testStartRotation_WifiOnly_FailOnce_Retry_ShouldStillHaveWifiTurnedOff()
+ throws Throwable {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+ // Click on WiFi-only option to toggle it off.
+ onView(withId(R.id.start_rotation_wifi_only_checkbox)).perform(click());
+ onView(withText(android.R.string.ok)).perform(click());
+
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(false /* isSuccessful */);
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ // Click try again to retry.
+ onView(withText(R.string.try_again)).perform(click());
+
+ mActivityRule.runOnUiThread(() -> {
+ testWPRotationInitializer.finishDownloadingFirstWallpaper(true /* isSuccessful */);
+ assertTrue(testWPRotationInitializer.isRotationInitialized());
+ assertFalse(testWPRotationInitializer.isWifiOnly());
+ });
+ }
+
+ @Test
+ public void testShowStartRotationDialog_ClickCancel_DismissesDialog() {
+ setActivityWithMockWallpapers(true /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ getActivity();
+
+ setUpFragmentForTesting();
+ TestWallpaperRotationInitializer
+ testWPRotationInitializer = (TestWallpaperRotationInitializer)
+ mTestCategory.getWallpaperRotationInitializer();
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+
+ onView(withId(R.id.daily_refresh)).perform(click());
+ onView(withId(R.id.start_rotation_wifi_only_checkbox)).check(matches(isDisplayed()));
+ // WiFi-only option should be checked by default.
+ onView(withId(R.id.start_rotation_wifi_only_checkbox)).check(matches(isChecked()));
+
+ // Click "Cancel" to dismiss the dialog.
+ onView(withText(android.R.string.cancel)).perform(click());
+
+ // Rotation was not initialized and dialog is no longer visible.
+ assertFalse(testWPRotationInitializer.isRotationInitialized());
+ onView(withId(R.id.start_rotation_wifi_only_checkbox)).check(doesNotExist());
+ }
+
+ /**
+ * Tests that when no title is present, a wallpaper tile's content description attribute is
+ * set to the first attribution.
+ */
+ @Test
+ public void testWallpaperHasContentDescriptionFromAttribution() {
+ setActivityWithMockWallpapers(false /* isRotationEnabled */,
+ WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED);
+ IndividualPickerActivity activity = getActivity();
+
+ RecyclerView recyclerView = activity.findViewById(R.id.wallpaper_grid);
+
+ RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(0);
+ assertEquals("Attribution 0", holder.itemView.findViewById(R.id.tile)
+ .getContentDescription());
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestAlarmManagerWrapper.java b/tests/src/com/android/wallpaper/testing/TestAlarmManagerWrapper.java
new file mode 100644
index 0000000..c9bbdd2
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestAlarmManagerWrapper.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.PendingIntent;
+
+import com.android.wallpaper.module.AlarmManagerWrapper;
+
+/**
+ * Mock of {@link AlarmManagerWrapper}.
+ */
+public class TestAlarmManagerWrapper implements AlarmManagerWrapper {
+
+ private int mExactAlarmSetCount;
+ private int mInexactAlarmSetCount;
+ private int mAlarmCanceledCount;
+
+ private long mLastInexactTriggerAtMillis;
+
+ @Override
+ public void set(int type, long triggerAtMillis, PendingIntent operation) {
+ mExactAlarmSetCount++;
+ }
+
+ @Override
+ public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
+ PendingIntent operation) {
+ mExactAlarmSetCount++;
+ }
+
+ @Override
+ public void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis,
+ PendingIntent operation) {
+ mInexactAlarmSetCount++;
+ mLastInexactTriggerAtMillis = triggerAtMillis;
+ }
+
+ @Override
+ public void cancel(PendingIntent operation) {
+ mAlarmCanceledCount++;
+ }
+
+ public int getExactAlarmSetCount() {
+ return mExactAlarmSetCount;
+ }
+
+ public int getInexactAlarmSetCount() {
+ return mInexactAlarmSetCount;
+ }
+
+ public int getAlarmCanceledCount() {
+ return mAlarmCanceledCount;
+ }
+
+ public long getLastInexactTriggerAtMillis() {
+ return mLastInexactTriggerAtMillis;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestAsset.java b/tests/src/com/android/wallpaper/testing/TestAsset.java
new file mode 100644
index 0000000..368919a
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestAsset.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 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.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.wallpaper.asset.Asset;
+
+
+/**
+ * Test implementation of Asset which blocks on Bitmap decoding operations.
+ */
+public final class TestAsset extends Asset {
+
+ private Bitmap mBitmap;
+ private boolean mIsCorrupt;
+
+ /**
+ * Constructs an asset underpinned by a 1x1 bitmap uniquely identifiable by the given pixel
+ * color.
+ *
+ * @param pixelColor Color of the asset's single pixel.
+ * @param isCorrupt Whether or not the asset is corrupt and fails to validly decode bitmaps and
+ * dimensions.
+ */
+ public TestAsset(int pixelColor, boolean isCorrupt) {
+ mIsCorrupt = isCorrupt;
+
+ if (!mIsCorrupt) {
+ mBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+ mBitmap.setPixel(0, 0, pixelColor);
+ } else {
+ mBitmap = null;
+ }
+ }
+
+ @Override
+ public void decodeBitmap(int targetWidth, int targetHeight, BitmapReceiver receiver) {
+ receiver.onBitmapDecoded(mBitmap);
+ }
+
+ @Override
+ public void decodeBitmapRegion(Rect unused, int targetWidth, int targetHeight,
+ BitmapReceiver receiver) {
+ receiver.onBitmapDecoded(mBitmap);
+ }
+
+ @Override
+ public void decodeRawDimensions(Activity unused, DimensionsReceiver receiver) {
+ receiver.onDimensionsDecoded(mIsCorrupt ? null : new Point(1, 1));
+ }
+
+ @Override
+ public boolean supportsTiling() {
+ return false;
+ }
+
+ @Override
+ public void loadDrawableWithTransition(
+ Context context,
+ ImageView imageView,
+ int transitionDurationMillis,
+ @Nullable DrawableLoadedListener drawableLoadedListener,
+ int placeholderColor) {
+ if (drawableLoadedListener != null) {
+ drawableLoadedListener.onDrawableLoaded();
+ }
+ }
+
+ /** Returns the bitmap synchronously. Convenience method for tests. */
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestBitmapCropper.java b/tests/src/com/android/wallpaper/testing/TestBitmapCropper.java
new file mode 100644
index 0000000..7daeeab
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestBitmapCropper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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.graphics.Bitmap;
+import android.graphics.Rect;
+
+import com.android.wallpaper.asset.Asset;
+import com.android.wallpaper.asset.Asset.BitmapReceiver;
+import com.android.wallpaper.module.BitmapCropper;
+
+/**
+ * Test double for BitmapCropper.
+ */
+public class TestBitmapCropper implements BitmapCropper {
+
+ private boolean mFailNextCall;
+
+ public TestBitmapCropper() {
+ mFailNextCall = false;
+ }
+
+ @Override
+ public void cropAndScaleBitmap(Asset asset, float scale, Rect cropRect,
+ Callback callback) {
+ if (mFailNextCall) {
+ callback.onError(null /* throwable */);
+ return;
+ }
+ // Crop rect in pixels of source image.
+ Rect scaledCropRect = new Rect(
+ Math.round((float) cropRect.left / scale),
+ Math.round((float) cropRect.top / scale),
+ Math.round((float) cropRect.right / scale),
+ Math.round((float) cropRect.bottom / scale));
+
+ asset.decodeBitmapRegion(scaledCropRect, cropRect.width(), cropRect.height(),
+ new BitmapReceiver() {
+ @Override
+ public void onBitmapDecoded(Bitmap bitmap) {
+ callback.onBitmapCropped(bitmap);
+ }
+ });
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java b/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java
new file mode 100644
index 0000000..310840c
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestCategoryProvider.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.os.Handler;
+
+import com.android.wallpaper.model.Category;
+import com.android.wallpaper.model.CategoryProvider;
+import com.android.wallpaper.model.CategoryReceiver;
+import com.android.wallpaper.model.ImageCategory;
+import com.android.wallpaper.model.WallpaperInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test implementation of {@link CategoryProvider}.
+ */
+public class TestCategoryProvider implements CategoryProvider {
+ private final List<Category> mCategories;
+
+ public TestCategoryProvider() {
+ Category category1 = new ImageCategory(
+ "My photos" /* title */,
+ "image_wallpapers" /* collection */,
+ 0 /* priority */);
+
+ ArrayList<WallpaperInfo> wallpapers = new ArrayList<>();
+ WallpaperInfo wallpaperInfo = new com.android.wallpaper.testing.TestWallpaperInfo(0);
+ wallpapers.add(wallpaperInfo);
+ Category category2 = new com.android.wallpaper.testing.TestWallpaperCategory(
+ "Test category", "init_collection", wallpapers,
+ 1 /* priority */);
+
+ mCategories = new ArrayList<>();
+ mCategories.add(category1);
+ mCategories.add(category2);
+ }
+
+ @Override
+ public void fetchCategories(CategoryReceiver receiver, boolean forceRefresh) {
+ // Mimic real behavior by fetching asynchronously.
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ List<Category> categories = getTestCategories();
+ for (Category category : categories) {
+ receiver.onCategoryReceived(category);
+ }
+ receiver.doneFetchingCategories();
+ }
+ });
+ }
+
+ @Override
+ public int getSize() {
+ return mCategories == null ? 0 : mCategories.size();
+ }
+
+ @Override
+ public Category getCategory(int index) {
+ return mCategories == null ? null : mCategories.get(index);
+ }
+
+ @Override
+ public Category getCategory(String collectionId) {
+ Category category;
+ for (int i = 0; i < mCategories.size(); i++) {
+ category = mCategories.get(i);
+ if (category.getCollectionId().equals(collectionId)) {
+ return category;
+ }
+ }
+ return null;
+ }
+
+ /** Returns a list of test Category objects used by this TestCategoryProvider. */
+ public List<Category> getTestCategories() {
+ return mCategories;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java b/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java
new file mode 100644
index 0000000..3e8c665
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestCurrentWallpaperInfoFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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.compat.BuildCompat;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.WallpaperRefresher;
+
+import java.util.List;
+
+/**
+ * Test double of {@link CurrentWallpaperInfoFactory}.
+ */
+public class TestCurrentWallpaperInfoFactory implements CurrentWallpaperInfoFactory {
+
+ private WallpaperRefresher mRefresher;
+
+ public TestCurrentWallpaperInfoFactory(Context context) {
+ mRefresher = InjectorProvider.getInjector().getWallpaperRefresher(
+ context.getApplicationContext());
+ }
+
+ @Override
+ public void createCurrentWallpaperInfos(final WallpaperInfoCallback callback,
+ boolean forceRefresh) {
+ mRefresher.refresh((homeWallpaperMetadata, lockWallpaperMetadata, presentationMode) -> {
+
+ WallpaperInfo homeWallpaper = createTestWallpaperInfo(
+ homeWallpaperMetadata.getAttributions(),
+ homeWallpaperMetadata.getActionUrl(),
+ homeWallpaperMetadata.getCollectionId());
+
+ WallpaperInfo lockWallpaper = null;
+ if (lockWallpaperMetadata != null && BuildCompat.isAtLeastN()) {
+ lockWallpaper = createTestWallpaperInfo(
+ lockWallpaperMetadata.getAttributions(),
+ lockWallpaperMetadata.getActionUrl(),
+ lockWallpaperMetadata.getCollectionId());
+ }
+
+ callback.onWallpaperInfoCreated(homeWallpaper, lockWallpaper, presentationMode);
+ });
+ }
+
+ private static WallpaperInfo createTestWallpaperInfo(List<String> attributions,
+ String actionUrl, String collectionId) {
+ TestWallpaperInfo wallpaper = new TestWallpaperInfo(TestWallpaperInfo.COLOR_BLACK);
+ wallpaper.setAttributions(attributions);
+ wallpaper.setActionUrl(actionUrl);
+ wallpaper.setCollectionId(collectionId);
+ return wallpaper;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestExploreIntentChecker.java b/tests/src/com/android/wallpaper/testing/TestExploreIntentChecker.java
new file mode 100644
index 0000000..dc1f1a8
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestExploreIntentChecker.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.Intent;
+import android.net.Uri;
+
+import com.android.wallpaper.module.ExploreIntentChecker;
+
+/**
+ * Test implementation of ExploreIntentChecker.
+ */
+public class TestExploreIntentChecker implements ExploreIntentChecker {
+
+ private boolean mViewHandlerExists;
+
+ public TestExploreIntentChecker() {
+ // True by default.
+ mViewHandlerExists = true;
+ }
+
+ @Override
+ public void fetchValidActionViewIntent(Uri uri, IntentReceiver receiver) {
+ Intent intent = mViewHandlerExists ? new Intent(Intent.ACTION_VIEW, uri) : null;
+ receiver.onIntentReceived(intent);
+ }
+
+ public void setViewHandlerExists(boolean exists) {
+ mViewHandlerExists = exists;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestFormFactorChecker.java b/tests/src/com/android/wallpaper/testing/TestFormFactorChecker.java
new file mode 100644
index 0000000..ba77172
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestFormFactorChecker.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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.module.FormFactorChecker;
+
+/**
+ * Test implementation of {@code FormFactorChecker}.
+ */
+public class TestFormFactorChecker implements FormFactorChecker {
+
+ @FormFactor
+ private int mFormFactor;
+
+ public TestFormFactorChecker() {
+ mFormFactor = FORM_FACTOR_MOBILE;
+ }
+
+ @FormFactor
+ @Override
+ public int getFormFactor() {
+ return mFormFactor;
+ }
+
+ public void setFormFactor(@FormFactor int formFactor) {
+ mFormFactor = formFactor;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestInjector.java b/tests/src/com/android/wallpaper/testing/TestInjector.java
new file mode 100644
index 0000000..0da755e
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestInjector.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2019 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 androidx.fragment.app.Fragment;
+
+import com.android.wallpaper.compat.WallpaperManagerCompat;
+import com.android.wallpaper.model.CategoryProvider;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.AlarmManagerWrapper;
+import com.android.wallpaper.module.BitmapCropper;
+import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
+import com.android.wallpaper.module.DefaultLiveWallpaperInfoFactory;
+import com.android.wallpaper.module.DrawableLayerResolver;
+import com.android.wallpaper.module.ExploreIntentChecker;
+import com.android.wallpaper.module.FormFactorChecker;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.LiveWallpaperInfoFactory;
+import com.android.wallpaper.module.LoggingOptInStatusProvider;
+import com.android.wallpaper.module.NetworkStatusNotifier;
+import com.android.wallpaper.module.PackageStatusNotifier;
+import com.android.wallpaper.module.PartnerProvider;
+import com.android.wallpaper.module.SystemFeatureChecker;
+import com.android.wallpaper.module.UserEventLogger;
+import com.android.wallpaper.module.WallpaperPersister;
+import com.android.wallpaper.module.WallpaperPreferences;
+import com.android.wallpaper.module.WallpaperRefresher;
+import com.android.wallpaper.module.WallpaperRotationRefresher;
+import com.android.wallpaper.monitor.PerformanceMonitor;
+import com.android.wallpaper.network.Requester;
+import com.android.wallpaper.picker.ImagePreviewFragment;
+import com.android.wallpaper.picker.individual.IndividualPickerFragment;
+
+/**
+ * Test implementation of the dependency injector.
+ */
+public class TestInjector implements Injector {
+
+ private BitmapCropper mBitmapCropper;
+ private CategoryProvider mCategoryProvider;
+ private PartnerProvider mPartnerProvider;
+ private WallpaperPreferences mPrefs;
+ private WallpaperPersister mWallpaperPersister;
+ private WallpaperRefresher mWallpaperRefresher;
+ private Requester mRequester;
+ private WallpaperManagerCompat mWallpaperManagerCompat;
+ private CurrentWallpaperInfoFactory mCurrentWallpaperInfoFactory;
+ private NetworkStatusNotifier mNetworkStatusNotifier;
+ private AlarmManagerWrapper mAlarmManagerWrapper;
+ private UserEventLogger mUserEventLogger;
+ private ExploreIntentChecker mExploreIntentChecker;
+ private SystemFeatureChecker mSystemFeatureChecker;
+ private FormFactorChecker mFormFactorChecker;
+ private WallpaperRotationRefresher mWallpaperRotationRefresher;
+ private PerformanceMonitor mPerformanceMonitor;
+ private LoggingOptInStatusProvider mLoggingOptInStatusProvider;
+
+ @Override
+ public BitmapCropper getBitmapCropper() {
+ if (mBitmapCropper == null) {
+ mBitmapCropper = new com.android.wallpaper.testing.TestBitmapCropper();
+ }
+ return mBitmapCropper;
+ }
+
+ @Override
+ public CategoryProvider getCategoryProvider(Context context) {
+ if (mCategoryProvider == null) {
+ mCategoryProvider = new TestCategoryProvider();
+ }
+ return mCategoryProvider;
+ }
+
+ @Override
+ public PartnerProvider getPartnerProvider(Context context) {
+ if (mPartnerProvider == null) {
+ mPartnerProvider = new TestPartnerProvider();
+ }
+ return mPartnerProvider;
+ }
+
+ @Override
+ public WallpaperPreferences getPreferences(Context context) {
+ if (mPrefs == null) {
+ mPrefs = new TestWallpaperPreferences();
+ }
+ return mPrefs;
+ }
+
+ @Override
+ public WallpaperPersister getWallpaperPersister(Context context) {
+ if (mWallpaperPersister == null) {
+ mWallpaperPersister = new TestWallpaperPersister(context.getApplicationContext());
+ }
+ return mWallpaperPersister;
+ }
+
+ @Override
+ public WallpaperRefresher getWallpaperRefresher(Context context) {
+ if (mWallpaperRefresher == null) {
+ mWallpaperRefresher = new TestWallpaperRefresher(context.getApplicationContext());
+ }
+ return mWallpaperRefresher;
+ }
+
+ @Override
+ public Requester getRequester(Context unused) {
+ return null;
+ }
+
+ @Override
+ public WallpaperManagerCompat getWallpaperManagerCompat(Context context) {
+ if (mWallpaperManagerCompat == null) {
+ mWallpaperManagerCompat = new com.android.wallpaper.testing.TestWallpaperManagerCompat(
+ context.getApplicationContext());
+ }
+ return mWallpaperManagerCompat;
+ }
+
+ @Override
+ public CurrentWallpaperInfoFactory getCurrentWallpaperFactory(Context context) {
+ if (mCurrentWallpaperInfoFactory == null) {
+ mCurrentWallpaperInfoFactory =
+ new TestCurrentWallpaperInfoFactory(context.getApplicationContext());
+ }
+ return mCurrentWallpaperInfoFactory;
+ }
+
+ @Override
+ public LoggingOptInStatusProvider getLoggingOptInStatusProvider(Context context) {
+ if (mLoggingOptInStatusProvider == null) {
+ mLoggingOptInStatusProvider = new TestLoggingOptInStatusProvider();
+ }
+ return mLoggingOptInStatusProvider;
+ }
+
+ @Override
+ public NetworkStatusNotifier getNetworkStatusNotifier(Context context) {
+ if (mNetworkStatusNotifier == null) {
+ mNetworkStatusNotifier = new TestNetworkStatusNotifier();
+ }
+ return mNetworkStatusNotifier;
+ }
+
+ @Override
+ public AlarmManagerWrapper getAlarmManagerWrapper(Context unused) {
+ if (mAlarmManagerWrapper == null) {
+ mAlarmManagerWrapper = new TestAlarmManagerWrapper();
+ }
+ return mAlarmManagerWrapper;
+ }
+
+ @Override
+ public UserEventLogger getUserEventLogger(Context unused) {
+ if (mUserEventLogger == null) {
+ mUserEventLogger = new com.android.wallpaper.testing.TestUserEventLogger();
+ }
+ return mUserEventLogger;
+ }
+
+ @Override
+ public ExploreIntentChecker getExploreIntentChecker(Context unused) {
+ if (mExploreIntentChecker == null) {
+ mExploreIntentChecker = new TestExploreIntentChecker();
+ }
+ return mExploreIntentChecker;
+ }
+
+ @Override
+ public SystemFeatureChecker getSystemFeatureChecker() {
+ if (mSystemFeatureChecker == null) {
+ mSystemFeatureChecker = new com.android.wallpaper.testing.TestSystemFeatureChecker();
+ }
+ return mSystemFeatureChecker;
+ }
+
+ @Override
+ public FormFactorChecker getFormFactorChecker(Context unused) {
+ if (mFormFactorChecker == null) {
+ mFormFactorChecker = new TestFormFactorChecker();
+ }
+ return mFormFactorChecker;
+ }
+
+ @Override
+ public WallpaperRotationRefresher getWallpaperRotationRefresher() {
+ if (mWallpaperRotationRefresher == null) {
+ mWallpaperRotationRefresher = (context, listener) -> {
+ // Not implemented
+ listener.onError();
+ };
+ }
+ return mWallpaperRotationRefresher;
+ }
+
+ @Override
+ public Fragment getPreviewFragment(Context context, WallpaperInfo wallpaperInfo, int mode,
+ boolean testingModeEnabled) {
+ return ImagePreviewFragment.newInstance(wallpaperInfo, mode, testingModeEnabled);
+ }
+
+ @Override
+ public PackageStatusNotifier getPackageStatusNotifier(Context context) {
+ return null;
+ }
+
+ @Override
+ public IndividualPickerFragment getIndividualPickerFragment(String collectionId) {
+ return IndividualPickerFragment.newInstance(collectionId);
+ }
+
+ @Override
+ public LiveWallpaperInfoFactory getLiveWallpaperInfoFactory(Context context) {
+ return new DefaultLiveWallpaperInfoFactory();
+ }
+
+ @Override
+ public DrawableLayerResolver getDrawableLayerResolver() {
+ return null;
+ }
+
+ @Override
+ public PerformanceMonitor getPerformanceMonitor() {
+ if (mPerformanceMonitor == null) {
+ mPerformanceMonitor = new TestPerformanceMonitor();
+ }
+ return mPerformanceMonitor;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestLoggingOptInStatusProvider.java b/tests/src/com/android/wallpaper/testing/TestLoggingOptInStatusProvider.java
new file mode 100644
index 0000000..f4434b1
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestLoggingOptInStatusProvider.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.module.LoggingOptInStatusProvider;
+
+/** Test implementation of {@link LoggingOptInStatusProvider}. */
+public class TestLoggingOptInStatusProvider implements LoggingOptInStatusProvider {
+
+ @Override
+ public void fetchOptInValue(OptInValueReceiver receiver) {
+ receiver.onOptInValueReady(true /* optedIn */);
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestNetworkStatusNotifier.java b/tests/src/com/android/wallpaper/testing/TestNetworkStatusNotifier.java
new file mode 100644
index 0000000..b09ee43
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestNetworkStatusNotifier.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.module.NetworkStatusNotifier;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test implementation of {@link NetworkStatusNotifier} which enables clients to manually notify
+ * listeners of a network status change.
+ */
+public class TestNetworkStatusNotifier implements NetworkStatusNotifier {
+
+ private List<Listener> mListeners;
+ @NetworkStatus
+ private int mNetworkStatus;
+
+ public TestNetworkStatusNotifier() {
+ mListeners = new ArrayList<>();
+ mNetworkStatus = NETWORK_CONNECTED;
+ }
+
+ @Override
+ public int getNetworkStatus() {
+ return mNetworkStatus;
+ }
+
+ @Override
+ public void registerListener(Listener listener) {
+ mListeners.add(listener);
+ listener.onNetworkChanged(mNetworkStatus);
+ }
+
+ @Override
+ public void unregisterListener(Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ public void setAndNotifyNetworkStatus(@NetworkStatus int networkStatus) {
+ mNetworkStatus = networkStatus;
+ for (Listener listener : mListeners) {
+ listener.onNetworkChanged(mNetworkStatus);
+ }
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestPartnerProvider.java b/tests/src/com/android/wallpaper/testing/TestPartnerProvider.java
new file mode 100644
index 0000000..fbdd0af
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestPartnerProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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.res.Resources;
+
+import com.android.wallpaper.module.PartnerProvider;
+
+import java.io.File;
+
+/**
+ * Test implementation for PartnerProvider.
+ */
+public class TestPartnerProvider implements PartnerProvider {
+ private File mLegacyWallpaperDirectory;
+
+ @Override
+ public Resources getResources() {
+ return null;
+ }
+
+ @Override
+ public File getLegacyWallpaperDirectory() {
+ return mLegacyWallpaperDirectory;
+ }
+
+ /**
+ * Sets the File to be returned by subsequent calls to getLegacyWallpaperDirectory().
+ *
+ * @param dir The legacy wallpaper directory.
+ */
+ public void setLegacyWallpaperDirectory(File dir) {
+ mLegacyWallpaperDirectory = dir;
+ }
+
+ @Override
+ public String getPackageName() {
+ return null;
+ }
+
+ @Override
+ public boolean shouldHideDefaultWallpaper() {
+ return false;
+ }
+}
diff --git a/src/com/android/wallpaper/module/LiveWallpaperStatusChecker.java b/tests/src/com/android/wallpaper/testing/TestPerformanceMonitor.java
index 67d87f8..7fe3ade 100755..100644
--- a/src/com/android/wallpaper/module/LiveWallpaperStatusChecker.java
+++ b/tests/src/com/android/wallpaper/testing/TestPerformanceMonitor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.wallpaper.module;
+package com.android.wallpaper.testing;
+
+import com.android.wallpaper.monitor.PerformanceMonitor;
/**
- * Reads whether the application's live wallpaper service is set to the device.
+ * No-op performance monitor for test.
*/
-public interface LiveWallpaperStatusChecker {
+public class TestPerformanceMonitor implements PerformanceMonitor {
- /**
- * Returns whether the live wallpaper for daily wallpapers is set to the device.
- */
- boolean isNoBackupImageWallpaperSet();
+ @Override
+ public void recordFullResPreviewLoadedMemorySnapshot() {
+ }
}
diff --git a/tests/src/com/android/wallpaper/testing/TestSystemFeatureChecker.java b/tests/src/com/android/wallpaper/testing/TestSystemFeatureChecker.java
new file mode 100644
index 0000000..775e693
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestSystemFeatureChecker.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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.SystemFeatureChecker;
+
+/**
+ * Test implementation of {@link SystemFeatureChecker}.
+ */
+public class TestSystemFeatureChecker implements SystemFeatureChecker {
+
+ private boolean mHasTelephony;
+
+ public TestSystemFeatureChecker() {
+ mHasTelephony = true;
+ }
+
+ @Override
+ public boolean hasTelephony(Context context) {
+ return mHasTelephony;
+ }
+
+ public void setHasTelephony(boolean hasTelephony) {
+ mHasTelephony = hasTelephony;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestUserEventLogger.java b/tests/src/com/android/wallpaper/testing/TestUserEventLogger.java
new file mode 100644
index 0000000..9f0489e
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestUserEventLogger.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 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.module.UserEventLogger;
+import com.android.wallpaper.module.WallpaperPersister.WallpaperPosition;
+
+/**
+ * Test implementation of {@link UserEventLogger}.
+ */
+public class TestUserEventLogger implements UserEventLogger {
+
+ private int mNumDailyRefreshTurnedOnEvents;
+ private int mNumCurrentWallpaperPreviewedEvents;
+ private int mNumActionClickedEvents;
+ private int mNumIndividualWallpaperSelectedEvents;
+ private int mNumCategorySelectedEvents;
+ private int mNumWallpaperSetEvents;
+ private int mNumWallpaperSetResultEvents;
+ private String mLastCollectionId;
+ private String mLastWallpaperId;
+ @WallpaperSetResult
+ private int mLastWallpaperSetResult;
+ private int mLastDailyRotationHour;
+ private int mNum1DayActiveLogs;
+ private int mNum7DayActiveLogs;
+ private int mNum14DayActiveLogs;
+ private int mNum28DayActiveLogs;
+ private int mLastDailyWallpaperRotationStatus;
+ private int mNumDaysDailyRotationFailed;
+ private int mNumDaysDailyRotationNotAttempted;
+ private int mLastDailyWallpaperUpdateResult;
+ private int mStandalonePreviewLaunches;
+ private int mNumRestores;
+ @WallpaperPosition
+ private int mWallpaperPosition;
+
+ public TestUserEventLogger() {
+ mLastDailyRotationHour = -1;
+ mLastDailyWallpaperRotationStatus = -1;
+ mNumDaysDailyRotationFailed = -1;
+ mNumDaysDailyRotationNotAttempted = -1;
+ }
+
+ @Override
+ public void logResumed(boolean provisioned, boolean wallpaper) {
+
+ }
+
+ @Override
+ public void logStopped() {
+
+ }
+
+ @Override
+ public void logAppLaunched() {
+ // Do nothing.
+ }
+
+ @Override
+ public void logDailyRefreshTurnedOn() {
+ mNumDailyRefreshTurnedOnEvents++;
+ }
+
+ public int getNumDailyRefreshTurnedOnEvents() {
+ return mNumDailyRefreshTurnedOnEvents;
+ }
+
+ @Override
+ public void logCurrentWallpaperPreviewed() {
+ mNumCurrentWallpaperPreviewedEvents++;
+ }
+
+ @Override
+ public void logActionClicked(String collectionId, int actionLabelResId) {
+ mNumActionClickedEvents++;
+ mLastCollectionId = collectionId;
+ }
+
+ public int getNumCurrentWallpaperPreviewedEvents() {
+ return mNumCurrentWallpaperPreviewedEvents;
+ }
+
+ public int getNumActionClickedEvents() {
+ return mNumActionClickedEvents;
+ }
+
+ @Override
+ public void logIndividualWallpaperSelected(String collectionId) {
+ mNumIndividualWallpaperSelectedEvents++;
+ mLastCollectionId = collectionId;
+ }
+
+ public int getNumIndividualWallpaperSelectedEvents() {
+ return mNumIndividualWallpaperSelectedEvents;
+ }
+
+ @Override
+ public void logCategorySelected(String collectionId) {
+ mNumCategorySelectedEvents++;
+ mLastCollectionId = collectionId;
+ }
+
+ public int getNumCategorySelectedEvents() {
+ return mNumCategorySelectedEvents;
+ }
+
+ @Override
+ public void logWallpaperSet(String collectionId, String wallpaperId) {
+ mNumWallpaperSetEvents++;
+ mLastCollectionId = collectionId;
+ mLastWallpaperId = wallpaperId;
+ }
+
+ @Override
+ public void logWallpaperSetResult(@WallpaperSetResult int result) {
+ mNumWallpaperSetResultEvents++;
+ mLastWallpaperSetResult = result;
+ }
+
+ @Override
+ public void logWallpaperSetFailureReason(@WallpaperSetFailureReason int reason) {
+ // No-op
+ }
+
+
+ @Override
+ public void logNumDailyWallpaperRotationsInLastWeek() {
+ // No-op
+ }
+
+ @Override
+ public void logNumDailyWallpaperRotationsPreviousDay() {
+ // No-op
+ }
+
+ @Override
+ public void logDailyWallpaperRotationHour(int hour) {
+ mLastDailyRotationHour = hour;
+ }
+
+ @Override
+ public void logDailyWallpaperDecodes(boolean decodes) {
+ // No-op
+ }
+
+ @Override
+ public void logRefreshDailyWallpaperButtonClicked() {
+ // No-op
+ }
+
+ @Override
+ public void logDailyWallpaperRotationStatus(int status) {
+ mLastDailyWallpaperRotationStatus = status;
+ }
+
+ @Override
+ public void logDailyWallpaperSetNextWallpaperResult(@DailyWallpaperUpdateResult int result) {
+ mLastDailyWallpaperUpdateResult = result;
+ }
+
+ @Override
+ public void logDailyWallpaperSetNextWallpaperCrash(@DailyWallpaperUpdateCrash int crash) {
+ // No-op
+ }
+
+ @Override
+ public void logNumDaysDailyRotationFailed(int days) {
+ mNumDaysDailyRotationFailed = days;
+ }
+
+ @Override
+ public void logDailyWallpaperMetadataRequestFailure(
+ @DailyWallpaperMetadataFailureReason int reason) {
+ // No-op
+ }
+
+ @Override
+ public void logNumDaysDailyRotationNotAttempted(int days) {
+ mNumDaysDailyRotationNotAttempted = days;
+ }
+
+ @Override
+ public void logStandalonePreviewLaunched() {
+ mStandalonePreviewLaunches++;
+ }
+
+ @Override
+ public void logStandalonePreviewImageUriHasReadPermission(boolean isReadPermissionGranted) {
+ // No-op
+ }
+
+ @Override
+ public void logStandalonePreviewStorageDialogApproved(boolean isApproved) {
+ // No-op
+ }
+
+ @Override
+ public void logWallpaperPresentationMode() {
+ // No-op
+ }
+
+ @Override
+ public void logRestored() {
+ mNumRestores++;
+ }
+
+ public int getNumWallpaperSetEvents() {
+ return mNumWallpaperSetEvents;
+ }
+
+ public String getLastCollectionId() {
+ return mLastCollectionId;
+ }
+
+ public String getLastWallpaperId() {
+ return mLastWallpaperId;
+ }
+
+ public int getNumWallpaperSetResultEvents() {
+ return mNumWallpaperSetResultEvents;
+ }
+
+ @WallpaperSetResult
+ public int getLastWallpaperSetResult() {
+ return mLastWallpaperSetResult;
+ }
+
+ public int getLastDailyRotationHour() {
+ return mLastDailyRotationHour;
+ }
+
+ public int getNum1DayActiveLogs() {
+ return mNum1DayActiveLogs;
+ }
+
+ public int getNum7DayActiveLogs() {
+ return mNum7DayActiveLogs;
+ }
+
+ public int getNum14DayActiveLogs() {
+ return mNum14DayActiveLogs;
+ }
+
+ public int getNum28DayActiveLogs() {
+ return mNum28DayActiveLogs;
+ }
+
+ public int getLastDailyWallpaperRotationStatus() {
+ return mLastDailyWallpaperRotationStatus;
+ }
+
+ public int getNumDaysDailyRotationFailed() {
+ return mNumDaysDailyRotationFailed;
+ }
+
+ public int getNumDaysDailyRotationNotAttempted() {
+ return mNumDaysDailyRotationNotAttempted;
+ }
+
+ public int getLastDailyWallpaperUpdateResult() {
+ return mLastDailyWallpaperUpdateResult;
+ }
+
+ public int getStandalonePreviewLaunches() {
+ return mStandalonePreviewLaunches;
+ }
+
+ public int getNumRestores() {
+ return mNumRestores;
+ }
+
+ public int getWallpaperPosition() {
+ return mWallpaperPosition;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperCategory.java b/tests/src/com/android/wallpaper/testing/TestWallpaperCategory.java
new file mode 100644
index 0000000..c69ecf8
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperCategory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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.model.WallpaperCategory;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.model.WallpaperRotationInitializer;
+import com.android.wallpaper.model.WallpaperRotationInitializer.RotationInitializationState;
+
+import java.util.List;
+
+/**
+ * Test-only subclass of {@link WallpaperCategory} which can be configured to provide a test double
+ * {@link WallpaperRotationInitializer}.
+ */
+public class TestWallpaperCategory extends WallpaperCategory {
+ private boolean mIsRotationEnabled;
+ private TestWallpaperRotationInitializer mWallpaperRotationInitializer;
+
+ public TestWallpaperCategory(String title, String collectionId, List<WallpaperInfo> wallpapers,
+ int priority) {
+ super(title, collectionId, wallpapers, priority);
+ mIsRotationEnabled = false;
+ mWallpaperRotationInitializer = new TestWallpaperRotationInitializer();
+ }
+
+ @Override
+ public WallpaperRotationInitializer getWallpaperRotationInitializer() {
+ return (mIsRotationEnabled) ? mWallpaperRotationInitializer : null;
+ }
+
+ @Override
+ public List<WallpaperInfo> getMutableWallpapers() {
+ return super.getMutableWallpapers();
+ }
+
+ /** Sets whether rotation is enabled on this category. */
+ public void setIsRotationEnabled(boolean isRotationEnabled) {
+ mIsRotationEnabled = isRotationEnabled;
+ }
+
+ public void setRotationInitializationState(@RotationInitializationState int rotationState) {
+ mWallpaperRotationInitializer.setRotationInitializationState(rotationState);
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java b/tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java
new file mode 100644
index 0000000..c0ccee6
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperInfo.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2019 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.WallpaperInfo;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test model object for a wallpaper coming from local drawable resources.
+ */
+public class TestWallpaperInfo extends WallpaperInfo {
+ public static final int COLOR_BLACK = 0;
+ public static final Parcelable.Creator<TestWallpaperInfo> CREATOR =
+ new Parcelable.Creator<TestWallpaperInfo>() {
+ @Override
+ public TestWallpaperInfo createFromParcel(Parcel in) {
+ return new TestWallpaperInfo(in);
+ }
+
+ @Override
+ public TestWallpaperInfo[] newArray(int size) {
+ return new TestWallpaperInfo[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 TestWallpaperInfo(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) {
+ mPixelColor = pixelColor;
+ mAttributions = Arrays.asList("Test wallpaper");
+ mWallpaperComponent = null;
+ mIsAssetCorrupt = false;
+ mBackupPermission = BACKUP_ALLOWED;
+ mWallpaperId = id;
+ }
+
+ private TestWallpaperInfo(Parcel 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 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) {
+ 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 TestWallpaperInfo) {
+ return mPixelColor == ((TestWallpaperInfo) object).mPixelColor;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mPixelColor;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperManagerCompat.java b/tests/src/com/android/wallpaper/testing/TestWallpaperManagerCompat.java
new file mode 100644
index 0000000..69f6839
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperManagerCompat.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 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.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.wallpaper.compat.WallpaperManagerCompat;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Test double for {@link WallpaperManagerCompat}. */
+public class TestWallpaperManagerCompat extends WallpaperManagerCompat {
+ private static final String TAG = "TestWPManagerCompat";
+
+ ParcelFileDescriptor mSystemParcelFd;
+ ParcelFileDescriptor mLockParcelFd;
+ int mHomeWallpaperId = 0;
+ int mLockWallpaperId = 0;
+
+ private boolean mAllowBackup;
+ private Context mAppContext;
+ private Drawable mTestDrawable;
+
+ public TestWallpaperManagerCompat(Context appContext) {
+ mAppContext = appContext;
+ mAllowBackup = true;
+ }
+
+ @Override
+ public int setStream(InputStream stream, Rect visibleCropHint, boolean allowBackup,
+ int whichWallpaper) throws IOException {
+ mAllowBackup = allowBackup;
+ return ++mHomeWallpaperId;
+ }
+
+ @Override
+ public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup,
+ int whichWallpaper) throws IOException {
+ mAllowBackup = allowBackup;
+ return ++mLockWallpaperId;
+ }
+
+ @Override
+ public ParcelFileDescriptor getWallpaperFile(int whichWallpaper) {
+ if (whichWallpaper == WallpaperManagerCompat.FLAG_SYSTEM) {
+ return mSystemParcelFd;
+ } else if (whichWallpaper == WallpaperManagerCompat.FLAG_LOCK) {
+ return mLockParcelFd;
+ } else {
+ // :(
+ return null;
+ }
+ }
+
+ @Override
+ public Drawable getDrawable() {
+ if (mTestDrawable != null) {
+ return mTestDrawable;
+ }
+
+ // Retrieve WallpaperManager using Context#getSystemService instead of
+ // WallpaperManager#getInstance so it can be mocked out in test.
+ WallpaperManager wallpaperManager =
+ (WallpaperManager) mAppContext.getSystemService(Context.WALLPAPER_SERVICE);
+ return wallpaperManager.getDrawable();
+ }
+
+ @Override
+ public int getWallpaperId(@WallpaperLocation int whichWallpaper) {
+ switch (whichWallpaper) {
+ case WallpaperManagerCompat.FLAG_SYSTEM:
+ return mHomeWallpaperId;
+ case WallpaperManagerCompat.FLAG_LOCK:
+ return mLockWallpaperId;
+ default:
+ throw new IllegalArgumentException(
+ "Wallpaper location must be one of FLAG_SYSTEM or "
+ + "FLAG_LOCK but the value " + whichWallpaper + " was provided.");
+ }
+ }
+
+ public void setWallpaperFile(int whichWallpaper, ParcelFileDescriptor file) {
+ if (whichWallpaper == WallpaperManagerCompat.FLAG_SYSTEM) {
+ mSystemParcelFd = file;
+ } else if (whichWallpaper == WallpaperManagerCompat.FLAG_LOCK) {
+ mLockParcelFd = file;
+ } else {
+ Log.e(TAG, "Called setWallpaperFile without a valid distinct 'which' argument.");
+ }
+ }
+
+ public void setWallpaperId(@WallpaperLocation int whichWallpaper, int wallpaperId) {
+ switch (whichWallpaper) {
+ case WallpaperManagerCompat.FLAG_SYSTEM:
+ mHomeWallpaperId = wallpaperId;
+ break;
+ case WallpaperManagerCompat.FLAG_LOCK:
+ mLockWallpaperId = wallpaperId;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Wallpaper location must be one of FLAG_SYSTEM or "
+ + "FLAG_LOCK but the value " + whichWallpaper + " was provided.");
+ }
+ }
+
+ public void setDrawable(Drawable drawable) {
+ mTestDrawable = drawable;
+ }
+
+ /** Returns whether backup is allowed for the last set wallpaper. */
+ public boolean isBackupAllowed() {
+ return mAllowBackup;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java b/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java
new file mode 100644
index 0000000..5fc9421
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperPersister.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2019 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.Bitmap;
+import android.graphics.Rect;
+
+import androidx.annotation.Nullable;
+
+import com.android.wallpaper.asset.Asset;
+import com.android.wallpaper.asset.Asset.BitmapReceiver;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.WallpaperChangedNotifier;
+import com.android.wallpaper.module.WallpaperPersister;
+import com.android.wallpaper.module.WallpaperPreferences;
+
+import java.util.List;
+
+/**
+ * Test double for {@link WallpaperPersister}.
+ */
+public class TestWallpaperPersister implements WallpaperPersister {
+
+ private Context mAppContext;
+ private WallpaperPreferences mPrefs;
+ private WallpaperChangedNotifier mWallpaperChangedNotifier;
+ private Bitmap mCurrentHomeWallpaper;
+ private Bitmap mCurrentLockWallpaper;
+ private Bitmap mPendingHomeWallpaper;
+ private Bitmap mPendingLockWallpaper;
+ private List<String> mHomeAttributions;
+ private String mHomeActionUrl;
+ @Destination
+ private int mDestination;
+ private WallpaperPersister.SetWallpaperCallback mCallback;
+ private boolean mFailNextCall;
+ private Rect mCropRect;
+ private float mScale;
+ @WallpaperPosition
+ private int mWallpaperPosition;
+
+ public TestWallpaperPersister(Context appContext) {
+ mAppContext = appContext;
+ mPrefs = InjectorProvider.getInjector().getPreferences(appContext);
+ mWallpaperChangedNotifier = WallpaperChangedNotifier.getInstance();
+
+ mCurrentHomeWallpaper = null;
+ mCurrentLockWallpaper = null;
+ mPendingHomeWallpaper = null;
+ mPendingLockWallpaper = null;
+ mFailNextCall = false;
+ mScale = -1.0f;
+ }
+
+ @Override
+ public void setIndividualWallpaper(final WallpaperInfo wallpaperInfo, Asset asset,
+ @Nullable final Rect cropRect, final float scale, final @Destination int destination,
+ final WallpaperPersister.SetWallpaperCallback callback) {
+ asset.decodeBitmap(50, 50, bitmap -> {
+ if (destination == DEST_HOME_SCREEN || destination == DEST_BOTH) {
+ mPendingHomeWallpaper = bitmap;
+ mPrefs.setHomeWallpaperAttributions(wallpaperInfo.getAttributions(mAppContext));
+ mPrefs.setWallpaperPresentationMode(
+ WallpaperPreferences.PRESENTATION_MODE_STATIC);
+ mPrefs.setHomeWallpaperRemoteId(wallpaperInfo.getWallpaperId());
+ }
+ if (destination == DEST_LOCK_SCREEN || destination == DEST_BOTH) {
+ mPendingLockWallpaper = bitmap;
+ mPrefs.setLockWallpaperAttributions(wallpaperInfo.getAttributions(mAppContext));
+ }
+ mDestination = destination;
+ mCallback = callback;
+ mCropRect = cropRect;
+ mScale = scale;
+ });
+ }
+
+ @Override
+ public void setIndividualWallpaperWithPosition(Activity activity, WallpaperInfo wallpaper,
+ @WallpaperPosition int wallpaperPosition, SetWallpaperCallback callback) {
+ wallpaper.getAsset(activity).decodeBitmap(50, 50, new BitmapReceiver() {
+ @Override
+ public void onBitmapDecoded(@Nullable Bitmap bitmap) {
+ mPendingHomeWallpaper = bitmap;
+ mPrefs.setHomeWallpaperAttributions(wallpaper.getAttributions(mAppContext));
+ mPrefs.setHomeWallpaperBaseImageUrl(wallpaper.getBaseImageUrl());
+ mPrefs.setHomeWallpaperActionUrl(wallpaper.getActionUrl(mAppContext));
+ mPrefs.setHomeWallpaperCollectionId(wallpaper.getCollectionId(mAppContext));
+ mPrefs.setHomeWallpaperRemoteId(wallpaper.getWallpaperId());
+ mPrefs.setWallpaperPresentationMode(WallpaperPreferences.PRESENTATION_MODE_STATIC);
+ mPendingLockWallpaper = bitmap;
+ mPrefs.setLockWallpaperAttributions(wallpaper.getAttributions(mAppContext));
+
+ mDestination = WallpaperPersister.DEST_BOTH;
+ mCallback = callback;
+ mWallpaperPosition = wallpaperPosition;
+ }
+ });
+ }
+
+ @Override
+ public boolean setWallpaperInRotation(Bitmap wallpaperBitmap, List<String> attributions,
+ int actionLabelRes, int actionIconRes, String actionUrl, String collectionId) {
+ if (mFailNextCall) {
+ return false;
+ }
+
+ mCurrentHomeWallpaper = wallpaperBitmap;
+ mCurrentLockWallpaper = wallpaperBitmap;
+ mHomeAttributions = attributions;
+ mHomeActionUrl = actionUrl;
+ return true;
+ }
+
+ @Override
+ public int setWallpaperBitmapInNextRotation(Bitmap wallpaperBitmap) {
+ mCurrentHomeWallpaper = wallpaperBitmap;
+ mCurrentLockWallpaper = wallpaperBitmap;
+ return 1;
+ }
+
+ @Override
+ public boolean finalizeWallpaperForNextRotation(List<String> attributions, String actionUrl,
+ int actionLabelRes, int actionIconRes, String collectionId, int wallpaperId) {
+ mHomeAttributions = attributions;
+ mHomeActionUrl = actionUrl;
+ return true;
+ }
+
+ /** Returns mock system wallpaper bitmap. */
+ public Bitmap getCurrentHomeWallpaper() {
+ return mCurrentHomeWallpaper;
+ }
+
+ /** Returns mock lock screen wallpaper bitmap. */
+ public Bitmap getCurrentLockWallpaper() {
+ return mCurrentLockWallpaper;
+ }
+
+ /** Returns mock home attributions. */
+ public List<String> getHomeAttributions() {
+ return mHomeAttributions;
+ }
+
+ /** Returns the home wallpaper action URL. */
+ public String getHomeActionUrl() {
+ return mHomeActionUrl;
+ }
+
+ /** Returns the Destination a wallpaper was most recently set on. */
+ @Destination
+ public int getLastDestination() {
+ return mDestination;
+ }
+
+ /**
+ * Sets whether the next "set wallpaper" operation should fail or succeed.
+ */
+ public void setFailNextCall(Boolean failNextCall) {
+ mFailNextCall = failNextCall;
+ }
+
+ /**
+ * Implemented so synchronous test methods can control the completion of what would otherwise be
+ * an asynchronous operation.
+ */
+ public void finishSettingWallpaper() {
+ if (mFailNextCall) {
+ mCallback.onError(null /* throwable */);
+ } else {
+ if (mDestination == DEST_HOME_SCREEN || mDestination == DEST_BOTH) {
+ mCurrentHomeWallpaper = mPendingHomeWallpaper;
+ mPendingHomeWallpaper = null;
+ }
+ if (mDestination == DEST_LOCK_SCREEN || mDestination == DEST_BOTH) {
+ mCurrentLockWallpaper = mPendingLockWallpaper;
+ mPendingLockWallpaper = null;
+ }
+ mCallback.onSuccess();
+ mWallpaperChangedNotifier.notifyWallpaperChanged();
+ }
+ }
+
+ @Override
+ public void setWallpaperInfoInPreview(WallpaperInfo wallpaperInfo) {
+ }
+
+ @Override
+ public void onLiveWallpaperSet() {
+ }
+
+ /** Returns the last requested wallpaper bitmap scale. */
+ public float getScale() {
+ return mScale;
+ }
+
+ /** Returns the last requested wallpaper crop. */
+ public Rect getCropRect() {
+ return mCropRect;
+ }
+
+ /** Returns the last selected wallpaper position option. */
+ @WallpaperPosition
+ public int getWallpaperPosition() {
+ return mWallpaperPosition;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java b/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java
new file mode 100644
index 0000000..715e81b
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperPreferences.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2019 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 androidx.annotation.Nullable;
+
+import com.android.wallpaper.module.WallpaperPreferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test implementation of the WallpaperPreferences interface. Just keeps prefs in memory.
+ */
+public class TestWallpaperPreferences implements WallpaperPreferences {
+
+ @PresentationMode
+ private int mWallpaperPresentationMode;
+
+ private List<String> mHomeScreenAttributions;
+ private long mHomeScreenBitmapHashCode;
+ private int mHomeWallpaperManagerId;
+ private String mHomeScreenPackageName;
+ private String mHomeActionUrl;
+ private String mHomeBaseImageUrl;
+ private String mHomeCollectionId;
+ private String mHomeWallpaperRemoteId;
+
+ private List<String> mLockScreenAttributions;
+ private long mLockScreenBitmapHashCode;
+ private int mLockWallpaperManagerId;
+ private String mLockActionUrl;
+ private String mLockCollectionId;
+
+ private List<Long> mDailyRotations;
+ private long mDailyWallpaperEnabledTimestamp;
+ private long mLastDailyLogTimestamp;
+ private long mLastAppActiveTimestamp;
+ private int mLastDailyWallpaperRotationStatus;
+ private long mLastDailyWallpaperRotationStatusTimestamp;
+ private long mLastSyncTimestamp;
+ @PendingWallpaperSetStatus
+ private int mPendingWallpaperSetStatus;
+ @PendingDailyWallpaperUpdateStatus
+ private int mPendingDailyWallpaperUpdateStatus;
+ private int mNumDaysDailyRotationFailed;
+ private int mNumDaysDailyRotationNotAttempted;
+ private int mHomeWallpaperActionLabelRes;
+ private int mHomeWallpaperActionIconRes;
+ private int mLockWallpaperActionLabelRes;
+ private int mLockWallpaperActionIconRes;
+
+ public TestWallpaperPreferences() {
+ mWallpaperPresentationMode = WallpaperPreferences.PRESENTATION_MODE_STATIC;
+ mHomeScreenAttributions = Arrays.asList("Android wallpaper");
+ mHomeScreenBitmapHashCode = 0;
+ mHomeWallpaperManagerId = 0;
+
+ mLockScreenAttributions = Arrays.asList("Android wallpaper");
+ mLockScreenBitmapHashCode = 0;
+ mLockWallpaperManagerId = 0;
+
+ mDailyRotations = new ArrayList<>();
+ mDailyWallpaperEnabledTimestamp = -1;
+ mLastDailyLogTimestamp = -1;
+ mLastDailyWallpaperRotationStatus = -1;
+ mLastDailyWallpaperRotationStatusTimestamp = 0;
+ mLastSyncTimestamp = 0;
+ mPendingWallpaperSetStatus = WALLPAPER_SET_NOT_PENDING;
+ }
+
+ @Override
+ public int getWallpaperPresentationMode() {
+ return mWallpaperPresentationMode;
+ }
+
+ @Override
+ public void setWallpaperPresentationMode(@PresentationMode int presentationMode) {
+ mWallpaperPresentationMode = presentationMode;
+ }
+
+ @Override
+ public List<String> getHomeWallpaperAttributions() {
+ return mHomeScreenAttributions;
+ }
+
+ @Override
+ public void setHomeWallpaperAttributions(List<String> attributions) {
+ mHomeScreenAttributions = attributions;
+ }
+
+ @Override
+ public String getHomeWallpaperActionUrl() {
+ return mHomeActionUrl;
+ }
+
+ @Override
+ public void setHomeWallpaperActionUrl(String actionUrl) {
+ mHomeActionUrl = actionUrl;
+ }
+
+ @Override
+ public int getHomeWallpaperActionLabelRes() {
+ return mHomeWallpaperActionLabelRes;
+ }
+
+ @Override
+ public void setHomeWallpaperActionLabelRes(int resId) {
+ mHomeWallpaperActionLabelRes = resId;
+ }
+
+ @Override
+ public int getHomeWallpaperActionIconRes() {
+ return mHomeWallpaperActionIconRes;
+ }
+
+ @Override
+ public void setHomeWallpaperActionIconRes(int resId) {
+ mHomeWallpaperActionIconRes = resId;
+ }
+
+ @Override
+ public String getHomeWallpaperBaseImageUrl() {
+ return mHomeBaseImageUrl;
+ }
+
+ @Override
+ public void setHomeWallpaperBaseImageUrl(String baseImageUrl) {
+ mHomeBaseImageUrl = baseImageUrl;
+ }
+
+ @Override
+ public String getHomeWallpaperCollectionId() {
+ return mHomeCollectionId;
+ }
+
+ @Override
+ public void setHomeWallpaperCollectionId(String collectionId) {
+ mHomeCollectionId = collectionId;
+ }
+
+ @Override
+ public String getHomeWallpaperBackingFileName() {
+ return null;
+ }
+
+ @Override
+ public void setHomeWallpaperBackingFileName(String fileName) {
+
+ }
+
+ @Override
+ public void clearHomeWallpaperMetadata() {
+ mHomeScreenAttributions = null;
+ mWallpaperPresentationMode = WallpaperPreferences.PRESENTATION_MODE_STATIC;
+ mHomeScreenBitmapHashCode = 0;
+ mHomeScreenPackageName = null;
+ mHomeWallpaperManagerId = 0;
+ }
+
+ @Override
+ public long getHomeWallpaperHashCode() {
+ return mHomeScreenBitmapHashCode;
+ }
+
+ @Override
+ public void setHomeWallpaperHashCode(long hashCode) {
+ mHomeScreenBitmapHashCode = hashCode;
+ }
+
+ @Override
+ public String getHomeWallpaperPackageName() {
+ return mHomeScreenPackageName;
+ }
+
+ @Override
+ public void setHomeWallpaperPackageName(String packageName) {
+ mHomeScreenPackageName = packageName;
+ }
+
+ @Override
+ public int getHomeWallpaperManagerId() {
+ return mHomeWallpaperManagerId;
+ }
+
+ @Override
+ public void setHomeWallpaperManagerId(int homeWallpaperId) {
+ mHomeWallpaperManagerId = homeWallpaperId;
+ }
+
+ @Override
+ public String getHomeWallpaperRemoteId() {
+ return mHomeWallpaperRemoteId;
+ }
+
+ @Override
+ public void setHomeWallpaperRemoteId(String wallpaperRemoteId) {
+ mHomeWallpaperRemoteId = wallpaperRemoteId;
+ }
+
+ @Override
+ public List<String> getLockWallpaperAttributions() {
+ return mLockScreenAttributions;
+ }
+
+ @Override
+ public void setLockWallpaperAttributions(List<String> attributions) {
+ mLockScreenAttributions = attributions;
+ }
+
+ @Override
+ public String getLockWallpaperActionUrl() {
+ return mLockActionUrl;
+ }
+
+ @Override
+ public void setLockWallpaperActionUrl(String actionUrl) {
+ mLockActionUrl = actionUrl;
+ }
+
+ @Override
+ public int getLockWallpaperActionLabelRes() {
+ return mLockWallpaperActionLabelRes;
+ }
+
+ @Override
+ public void setLockWallpaperActionLabelRes(int resId) {
+ mLockWallpaperActionLabelRes = resId;
+ }
+
+ @Override
+ public int getLockWallpaperActionIconRes() {
+ return mLockWallpaperActionIconRes;
+ }
+
+ @Override
+ public void setLockWallpaperActionIconRes(int resId) {
+ mLockWallpaperActionIconRes = resId;
+ }
+
+ @Override
+ public String getLockWallpaperCollectionId() {
+ return mLockCollectionId;
+ }
+
+ @Override
+ public void setLockWallpaperCollectionId(String collectionId) {
+ mLockCollectionId = collectionId;
+ }
+
+ @Override
+ public String getLockWallpaperBackingFileName() {
+ return null;
+ }
+
+ @Override
+ public void setLockWallpaperBackingFileName(String fileName) {
+
+ }
+
+ @Override
+ public void clearLockWallpaperMetadata() {
+ mLockScreenAttributions = null;
+ mLockScreenBitmapHashCode = 0;
+ mLockWallpaperManagerId = 0;
+ }
+
+ @Override
+ public long getLockWallpaperHashCode() {
+ return mLockScreenBitmapHashCode;
+ }
+
+ @Override
+ public void setLockWallpaperHashCode(long hashCode) {
+ mLockScreenBitmapHashCode = hashCode;
+ }
+
+ @Override
+ public int getLockWallpaperId() {
+ return mLockWallpaperManagerId;
+ }
+
+ @Override
+ public void setLockWallpaperId(int lockWallpaperId) {
+ mLockWallpaperManagerId = lockWallpaperId;
+ }
+
+ @Override
+ public void addDailyRotation(long timestamp) {
+ mDailyRotations.add(timestamp);
+ }
+
+ @Override
+ public long getLastDailyRotationTimestamp() {
+ if (mDailyRotations.size() == 0) {
+ return -1;
+ }
+
+ return mDailyRotations.get(mDailyRotations.size() - 1);
+ }
+
+ @Override
+ public List<Long> getDailyRotationsInLastWeek() {
+ return mDailyRotations;
+ }
+
+ @Nullable
+ @Override
+ public List<Long> getDailyRotationsPreviousDay() {
+ return null;
+ }
+
+ @Override
+ public long getDailyWallpaperEnabledTimestamp() {
+ return mDailyWallpaperEnabledTimestamp;
+ }
+
+ @Override
+ public void setDailyWallpaperEnabledTimestamp(long timestamp) {
+ mDailyWallpaperEnabledTimestamp = timestamp;
+ }
+
+ @Override
+ public void clearDailyRotations() {
+ mDailyRotations.clear();
+ }
+
+ @Override
+ public long getLastDailyLogTimestamp() {
+ return mLastDailyLogTimestamp;
+ }
+
+ @Override
+ public void setLastDailyLogTimestamp(long timestamp) {
+ mLastDailyLogTimestamp = timestamp;
+ }
+
+ @Override
+ public long getLastAppActiveTimestamp() {
+ return mLastAppActiveTimestamp;
+ }
+
+ @Override
+ public void setLastAppActiveTimestamp(long timestamp) {
+ mLastAppActiveTimestamp = timestamp;
+ }
+
+ @Override
+ public void setDailyWallpaperRotationStatus(int status, long timestamp) {
+ mLastDailyWallpaperRotationStatus = status;
+ mLastDailyWallpaperRotationStatusTimestamp = timestamp;
+ }
+
+ @Override
+ public int getDailyWallpaperLastRotationStatus() {
+ return mLastDailyWallpaperRotationStatus;
+ }
+
+ @Override
+ public long getDailyWallpaperLastRotationStatusTimestamp() {
+ return mLastDailyWallpaperRotationStatusTimestamp;
+ }
+
+ @Override
+ public long getLastSyncTimestamp() {
+ return mLastSyncTimestamp;
+ }
+
+ @Override
+ public void setLastSyncTimestamp(long timestamp) {
+ mLastSyncTimestamp = timestamp;
+ }
+
+ @Override
+ public void setPendingWallpaperSetStatusSync(@PendingWallpaperSetStatus int setStatus) {
+ mPendingWallpaperSetStatus = setStatus;
+ }
+
+ @Override
+ public int getPendingWallpaperSetStatus() {
+ return mPendingWallpaperSetStatus;
+ }
+
+ @Override
+ public void setPendingWallpaperSetStatus(@PendingWallpaperSetStatus int setStatus) {
+ mPendingWallpaperSetStatus = setStatus;
+ }
+
+ @Override
+ public void setPendingDailyWallpaperUpdateStatusSync(
+ @PendingDailyWallpaperUpdateStatus int updateStatus) {
+ mPendingDailyWallpaperUpdateStatus = updateStatus;
+ }
+
+ @Override
+ public int getPendingDailyWallpaperUpdateStatus() {
+ return mPendingDailyWallpaperUpdateStatus;
+ }
+
+ @Override
+ public void setPendingDailyWallpaperUpdateStatus(
+ @PendingDailyWallpaperUpdateStatus int updateStatus) {
+ mPendingDailyWallpaperUpdateStatus = updateStatus;
+ }
+
+ @Override
+ public void incrementNumDaysDailyRotationFailed() {
+ mNumDaysDailyRotationFailed++;
+ }
+
+ @Override
+ public int getNumDaysDailyRotationFailed() {
+ return mNumDaysDailyRotationFailed;
+ }
+
+ public void setNumDaysDailyRotationFailed(int days) {
+ mNumDaysDailyRotationFailed = days;
+ }
+
+ @Override
+ public void resetNumDaysDailyRotationFailed() {
+ mNumDaysDailyRotationFailed = 0;
+ }
+
+ @Override
+ public void incrementNumDaysDailyRotationNotAttempted() {
+ mNumDaysDailyRotationNotAttempted++;
+ }
+
+ @Override
+ public int getNumDaysDailyRotationNotAttempted() {
+ return mNumDaysDailyRotationNotAttempted;
+ }
+
+ public void setNumDaysDailyRotationNotAttempted(int days) {
+ mNumDaysDailyRotationNotAttempted = days;
+ }
+
+ @Override
+ public void resetNumDaysDailyRotationNotAttempted() {
+ mNumDaysDailyRotationNotAttempted = 0;
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperRefresher.java b/tests/src/com/android/wallpaper/testing/TestWallpaperRefresher.java
new file mode 100644
index 0000000..97961fe
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperRefresher.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.WallpaperManager;
+import android.content.Context;
+
+import com.android.wallpaper.compat.BuildCompat;
+import com.android.wallpaper.model.WallpaperMetadata;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.WallpaperPreferences;
+import com.android.wallpaper.module.WallpaperRefresher;
+
+/**
+ * Test implementation of {@link WallpaperRefresher} which simply provides whatever metadata is
+ * saved in WallpaperPreferences and the image wallpaper set to {@link WallpaperManager}.
+ */
+public class TestWallpaperRefresher implements WallpaperRefresher {
+
+ private final Context mAppContext;
+
+ /**
+ * @param context The application's context.
+ */
+ public TestWallpaperRefresher(Context context) {
+ mAppContext = context.getApplicationContext();
+ }
+
+ @Override
+ public void refresh(RefreshListener listener) {
+
+ WallpaperPreferences prefs = InjectorProvider.getInjector().getPreferences(mAppContext);
+
+ if (BuildCompat.isAtLeastN() && prefs.getLockWallpaperId() > 0) {
+ listener.onRefreshed(
+ new WallpaperMetadata(
+ prefs.getHomeWallpaperAttributions(),
+ prefs.getHomeWallpaperActionUrl(),
+ prefs.getHomeWallpaperActionLabelRes(),
+ prefs.getHomeWallpaperActionIconRes(),
+ prefs.getHomeWallpaperCollectionId(),
+ prefs.getHomeWallpaperBackingFileName(),
+ null /* wallpaperComponent */),
+ new WallpaperMetadata(
+ prefs.getLockWallpaperAttributions(),
+ prefs.getLockWallpaperActionUrl(),
+ prefs.getLockWallpaperActionLabelRes(),
+ prefs.getLockWallpaperActionIconRes(),
+ prefs.getLockWallpaperCollectionId(),
+ prefs.getLockWallpaperBackingFileName(),
+ null /* wallpaperComponent */),
+ prefs.getWallpaperPresentationMode());
+ } else {
+ listener.onRefreshed(
+ new WallpaperMetadata(
+ prefs.getHomeWallpaperAttributions(),
+ prefs.getHomeWallpaperActionUrl(),
+ prefs.getHomeWallpaperActionLabelRes(),
+ prefs.getHomeWallpaperActionIconRes(),
+ prefs.getHomeWallpaperCollectionId(),
+ prefs.getHomeWallpaperBackingFileName(),
+ null /* wallpaperComponent */),
+ null,
+ prefs.getWallpaperPresentationMode());
+ }
+ }
+}
diff --git a/tests/src/com/android/wallpaper/testing/TestWallpaperRotationInitializer.java b/tests/src/com/android/wallpaper/testing/TestWallpaperRotationInitializer.java
new file mode 100644
index 0000000..9494d19
--- /dev/null
+++ b/tests/src/com/android/wallpaper/testing/TestWallpaperRotationInitializer.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 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 android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.wallpaper.model.WallpaperRotationInitializer;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.WallpaperPreferences;
+
+/**
+ * Test implementation of {@link WallpaperRotationInitializer}.
+ */
+public class TestWallpaperRotationInitializer implements WallpaperRotationInitializer {
+
+ private boolean mIsRotationInitialized;
+ @NetworkPreference
+ private int mNetworkPreference;
+ private Listener mListener;
+ @RotationInitializationState
+ private int mRotationInitializationState;
+
+ TestWallpaperRotationInitializer() {
+ mIsRotationInitialized = false;
+ mNetworkPreference = NETWORK_PREFERENCE_WIFI_ONLY;
+ mRotationInitializationState = WallpaperRotationInitializer.ROTATION_NOT_INITIALIZED;
+ }
+
+ TestWallpaperRotationInitializer(@RotationInitializationState int rotationState) {
+ mIsRotationInitialized = false;
+ mNetworkPreference = NETWORK_PREFERENCE_WIFI_ONLY;
+ mRotationInitializationState = rotationState;
+ }
+
+ private TestWallpaperRotationInitializer(Parcel unused) {
+ mIsRotationInitialized = false;
+ mNetworkPreference = NETWORK_PREFERENCE_WIFI_ONLY;
+ }
+
+ @Override
+ public void setFirstWallpaperInRotation(Context context,
+ @NetworkPreference int networkPreference,
+ Listener listener) {
+ mListener = listener;
+ mNetworkPreference = networkPreference;
+ }
+
+ @Override
+ public boolean startRotation(Context appContext) {
+ WallpaperPreferences wallpaperPreferences =
+ InjectorProvider.getInjector().getPreferences(appContext);
+ wallpaperPreferences.setWallpaperPresentationMode(
+ WallpaperPreferences.PRESENTATION_MODE_ROTATING);
+ return true;
+ }
+
+ @Override
+ public void fetchRotationInitializationState(Context context, RotationStateListener listener) {
+ listener.onRotationStateReceived(mRotationInitializationState);
+ }
+
+ @Override
+ public int getRotationInitializationStateDirty(Context context) {
+ return mRotationInitializationState;
+ }
+
+ /** Sets the mocked rotation initialization state. */
+ public void setRotationInitializationState(@RotationInitializationState int rotationState) {
+ mRotationInitializationState = rotationState;
+ }
+
+ /**
+ * Simulates completion of the asynchronous task to download the first wallpaper in a rotation..
+ *
+ * @param isSuccessful Whether the first wallpaper downloaded successfully.
+ */
+ public void finishDownloadingFirstWallpaper(boolean isSuccessful) {
+ if (isSuccessful) {
+ mIsRotationInitialized = true;
+ mListener.onFirstWallpaperInRotationSet();
+ } else {
+ mIsRotationInitialized = false;
+ mListener.onError();
+ }
+ }
+
+ /** Returns whether a wallpaper rotation is initialized. */
+ public boolean isRotationInitialized() {
+ return mIsRotationInitialized;
+ }
+
+ /** Returns whether a wallpaper rotation is enabled for WiFi-only. */
+ public boolean isWifiOnly() {
+ return mNetworkPreference == NETWORK_PREFERENCE_WIFI_ONLY;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<TestWallpaperRotationInitializer> CREATOR =
+ new Parcelable.Creator<TestWallpaperRotationInitializer>() {
+ @Override
+ public TestWallpaperRotationInitializer createFromParcel(Parcel in) {
+ return new TestWallpaperRotationInitializer(in);
+ }
+
+ @Override
+ public TestWallpaperRotationInitializer[] newArray(int size) {
+ return new TestWallpaperRotationInitializer[size];
+ }
+ };
+}