1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.wallpaper.module;
17 
18 import static android.app.WallpaperManager.FLAG_LOCK;
19 import static android.app.WallpaperManager.FLAG_SYSTEM;
20 
21 import static com.android.wallpaper.module.WallpaperPersister.DEST_BOTH;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.spy;
27 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
28 
29 import android.app.WallpaperManager;
30 import android.content.Context;
31 import android.graphics.drawable.BitmapDrawable;
32 import android.util.Log;
33 
34 import androidx.annotation.Nullable;
35 import androidx.test.platform.app.InstrumentationRegistry;
36 
37 import com.android.wallpaper.model.WallpaperInfo;
38 import com.android.wallpaper.module.DefaultWallpaperPersisterTest.TestSetWallpaperCallback.SetWallpaperStatus;
39 import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
40 import com.android.wallpaper.module.logging.TestUserEventLogger;
41 import com.android.wallpaper.testing.FakeDisplaysProvider;
42 import com.android.wallpaper.testing.TestAsset;
43 import com.android.wallpaper.testing.TestBitmapCropper;
44 import com.android.wallpaper.testing.TestCurrentWallpaperInfoFactory;
45 import com.android.wallpaper.testing.TestInjector;
46 import com.android.wallpaper.testing.TestStaticWallpaperInfo;
47 import com.android.wallpaper.testing.TestWallpaperPreferences;
48 import com.android.wallpaper.testing.TestWallpaperStatusChecker;
49 import com.android.wallpaper.util.DisplayUtils;
50 
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.robolectric.RobolectricTestRunner;
55 import org.robolectric.android.util.concurrent.PausedExecutorService;
56 import org.robolectric.shadows.ShadowPausedAsyncTask;
57 
58 import java.util.ArrayList;
59 import java.util.List;
60 
61 @RunWith(RobolectricTestRunner.class)
62 public class DefaultWallpaperPersisterTest {
63     private static final String TAG = "DefaultWallpaperPersisterTest";
64     private static final String ACTION_URL = "http://google.com";
65 
66     private Context mContext;
67     /** DefaultWallpaperPersister object under test */
68     private DefaultWallpaperPersister mPersister;
69     /** Spy on real WallpaperManager instance  */
70     private WallpaperManager mManager;
71     /** Fake instance of WallpaperPreferences */
72     private TestWallpaperPreferences mPrefs;
73     /** Executor to use for AsyncTask */
74     private final PausedExecutorService mPausedExecutor = new PausedExecutorService();
75 
76     @Before
setUp()77     public void setUp() {
78         InjectorProvider.setInjector(new TestInjector(new TestUserEventLogger()));
79         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
80         mManager = spy(WallpaperManager.getInstance(mContext));
81         mPrefs = new TestWallpaperPreferences();
82         WallpaperChangedNotifier changedNotifier = spy(WallpaperChangedNotifier.getInstance());
83         DisplayUtils displayUtils = new DisplayUtils(mContext, new FakeDisplaysProvider(mContext));
84         TestBitmapCropper cropper = new TestBitmapCropper();
85         TestWallpaperStatusChecker statusChecker = new TestWallpaperStatusChecker();
86         TestCurrentWallpaperInfoFactory wallpaperInfoFactory =
87                 new TestCurrentWallpaperInfoFactory(mContext);
88 
89         mPersister = new DefaultWallpaperPersister(mContext, mManager, mPrefs, changedNotifier,
90                 displayUtils, cropper, statusChecker, wallpaperInfoFactory, false);
91     }
92 
93     @Test
isSeparateLockScreenWallpaperSet_trueIfSet()94     public void isSeparateLockScreenWallpaperSet_trueIfSet() {
95         doReturn(-1).when(mManager).getWallpaperId(FLAG_LOCK);
96 
97         assertThat(mPersister.getDefaultWhichWallpaper()).isEqualTo(FLAG_SYSTEM | FLAG_LOCK);
98     }
99 
100     @Test
isSeparateLockScreenWallpaperSet_falseIfUnset()101     public void isSeparateLockScreenWallpaperSet_falseIfUnset() {
102         doReturn(1).when(mManager).getWallpaperId(FLAG_LOCK);
103 
104         assertThat(mPersister.getDefaultWhichWallpaper()).isEqualTo(FLAG_SYSTEM);
105     }
106 
107     @Test
setBitmapWallpaper_succeeds()108     public void setBitmapWallpaper_succeeds() {
109         TestStaticWallpaperInfo wallpaperInfo = newStaticWallpaperInfo();
110         prepareWallpaperSetFromInfo(wallpaperInfo);
111         TestSetWallpaperCallback callback = new TestSetWallpaperCallback();
112 
113         mPersister.setIndividualWallpaper(wallpaperInfo, wallpaperInfo.getAsset(mContext), null,
114                 1.0f, DEST_BOTH, callback);
115 
116         verifyWallpaperSetSuccess(callback);
117     }
118 
119     @Test
setBitmapWallpaper_setsActionUrl()120     public void setBitmapWallpaper_setsActionUrl() {
121         TestStaticWallpaperInfo wallpaperInfo = newStaticWallpaperInfo();
122         prepareWallpaperSetFromInfo(wallpaperInfo);
123         TestSetWallpaperCallback callback = new TestSetWallpaperCallback();
124 
125         mPersister.setIndividualWallpaper(wallpaperInfo, wallpaperInfo.getAsset(mContext), null,
126                 1.0f, DEST_BOTH, callback);
127 
128         verifyWallpaperSetSuccess(callback);
129         assertThat(mPrefs.getHomeWallpaperActionUrl()).isEqualTo(ACTION_URL);
130         assertThat(mPrefs.getLockWallpaperActionUrl()).isEqualTo(ACTION_URL);
131     }
132 
133      // Creates a basic test wallpaper info instance.
newStaticWallpaperInfo()134     private static TestStaticWallpaperInfo newStaticWallpaperInfo() {
135         List<String> attributions = new ArrayList<>();
136         attributions.add("Title");
137         attributions.add("Subtitle 1");
138         attributions.add("Subtitle 2");
139         TestStaticWallpaperInfo wallpaperInfo = new TestStaticWallpaperInfo(
140                 TestStaticWallpaperInfo.COLOR_DEFAULT);
141         wallpaperInfo.setAttributions(attributions);
142         wallpaperInfo.setCollectionId("collectionStatic");
143         wallpaperInfo.setWallpaperId("wallpaperStatic");
144         wallpaperInfo.setActionUrl(ACTION_URL);
145         return wallpaperInfo;
146     }
147 
148     // Call this method to prepare for a call to setIndividualWallpaper with non-streamable bitmap.
prepareWallpaperSetFromInfo(TestStaticWallpaperInfo wallpaperInfo)149     private void prepareWallpaperSetFromInfo(TestStaticWallpaperInfo wallpaperInfo) {
150         // Retrieve the bitmap to be set by the given WallpaperInfo, and override the return value
151         // from WallpaperManager.getDrawable().
152         TestAsset asset = (TestAsset) wallpaperInfo.getAsset(mContext);
153         doReturn(new BitmapDrawable(mContext.getResources(), asset.getBitmap())).when(mManager)
154                 .getDrawable();
155         // Override the background executor for AsyncTask to that we can explicitly execute its
156         // tasks - otherwise this will remain in the queue even after main looper idle.
157         ShadowPausedAsyncTask.overrideExecutor(mPausedExecutor);
158     }
159 
verifyWallpaperSetSuccess(TestSetWallpaperCallback callback)160     private void verifyWallpaperSetSuccess(TestSetWallpaperCallback callback) {
161         // Execute pending Asset#decodeBitmap; queues SetWallpaperTask background job
162         shadowMainLooper().idle();
163         // Execute SetWallpaperTask background job; queues onPostExecute on main thread
164         mPausedExecutor.runAll();
165         // Execute SetWallpaperTask#onPostExecute
166         shadowMainLooper().idle();
167 
168         assertThat(callback.getStatus()).isEqualTo(SetWallpaperStatus.SUCCESS);
169     }
170 
171     /**
172      * Simple wallpaper callback to either record success or log on failure.
173      */
174     static class TestSetWallpaperCallback implements SetWallpaperCallback {
175         enum SetWallpaperStatus {
176             UNCALLED,
177             SUCCESS,
178             FAILURE
179         }
180         SetWallpaperStatus mStatus = SetWallpaperStatus.UNCALLED;
181         @Override
onSuccess(WallpaperInfo wallpaperInfo, int destination)182         public void onSuccess(WallpaperInfo wallpaperInfo, int destination) {
183             mStatus = SetWallpaperStatus.SUCCESS;
184         }
185 
186         @Override
onError(@ullable Throwable throwable)187         public void onError(@Nullable Throwable throwable) {
188             mStatus = SetWallpaperStatus.FAILURE;
189             Log.e(TAG, "Set wallpaper failed", throwable);
190         }
191 
getStatus()192         public SetWallpaperStatus getStatus() {
193             return mStatus;
194         }
195     }
196 }
197