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 kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher; 26 27 import static org.mockito.Mockito.doReturn; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.spy; 30 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; 31 32 import android.app.WallpaperManager; 33 import android.content.Context; 34 import android.graphics.drawable.BitmapDrawable; 35 import android.util.Log; 36 37 import androidx.annotation.Nullable; 38 import androidx.test.platform.app.InstrumentationRegistry; 39 40 import com.android.wallpaper.model.WallpaperInfo; 41 import com.android.wallpaper.module.DefaultWallpaperPersisterTest.TestSetWallpaperCallback.SetWallpaperStatus; 42 import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback; 43 import com.android.wallpaper.module.logging.TestUserEventLogger; 44 import com.android.wallpaper.network.Requester; 45 import com.android.wallpaper.picker.category.wrapper.WallpaperCategoryWrapper; 46 import com.android.wallpaper.picker.customization.data.repository.WallpaperRepository; 47 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor; 48 import com.android.wallpaper.testing.FakeCurrentWallpaperInfoFactory; 49 import com.android.wallpaper.testing.FakeDisplaysProvider; 50 import com.android.wallpaper.testing.FakeWallpaperClient; 51 import com.android.wallpaper.testing.FakeWallpaperRefresher; 52 import com.android.wallpaper.testing.TestAsset; 53 import com.android.wallpaper.testing.TestBitmapCropper; 54 import com.android.wallpaper.testing.TestInjector; 55 import com.android.wallpaper.testing.TestPackageStatusNotifier; 56 import com.android.wallpaper.testing.TestStaticWallpaperInfo; 57 import com.android.wallpaper.testing.TestWallpaperPreferences; 58 import com.android.wallpaper.testing.TestWallpaperStatusChecker; 59 import com.android.wallpaper.util.DisplayUtils; 60 import com.android.wallpaper.util.DisplaysProvider; 61 62 import kotlinx.coroutines.test.TestDispatcher; 63 import kotlinx.coroutines.test.TestScope; 64 import kotlinx.coroutines.test.TestScopeKt; 65 66 import org.junit.Before; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.robolectric.RobolectricTestRunner; 70 import org.robolectric.android.util.concurrent.PausedExecutorService; 71 import org.robolectric.shadows.ShadowPausedAsyncTask; 72 73 import java.util.ArrayList; 74 import java.util.List; 75 76 77 @RunWith(RobolectricTestRunner.class) 78 public class DefaultWallpaperPersisterTest { 79 private static final String TAG = "DefaultWallpaperPersisterTest"; 80 private static final String ACTION_URL = "http://google.com"; 81 82 private Context mContext; 83 /** DefaultWallpaperPersister object under test */ 84 private DefaultWallpaperPersister mPersister; 85 /** Spy on real WallpaperManager instance */ 86 private WallpaperManager mManager; 87 /** Fake instance of WallpaperPreferences */ 88 private TestWallpaperPreferences mPrefs; 89 /** Executor to use for AsyncTask */ 90 private final PausedExecutorService mPausedExecutor = new PausedExecutorService(); 91 92 private TestPackageStatusNotifier mTestPackageStatusNotifier; 93 94 @Before setUp()95 public void setUp() { 96 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 97 98 mManager = spy(WallpaperManager.getInstance(mContext)); 99 mPrefs = new TestWallpaperPreferences(); 100 WallpaperChangedNotifier changedNotifier = spy(WallpaperChangedNotifier.getInstance()); 101 DisplayUtils displayUtils = new DisplayUtils(mContext, new FakeDisplaysProvider(mContext)); 102 TestBitmapCropper cropper = new TestBitmapCropper(); 103 TestWallpaperStatusChecker statusChecker = new TestWallpaperStatusChecker(); 104 TestDispatcher testDispatcher = StandardTestDispatcher(null, null); 105 TestScope testScope = TestScopeKt.TestScope(testDispatcher); 106 mTestPackageStatusNotifier = new TestPackageStatusNotifier(); 107 WallpaperInteractor wallpaperInteractor = 108 new WallpaperInteractor( 109 new WallpaperRepository( 110 testScope.getBackgroundScope(), 111 new FakeWallpaperClient(), 112 new TestWallpaperPreferences(), 113 testDispatcher 114 ) 115 ); 116 FakeWallpaperRefresher refresher = new FakeWallpaperRefresher(mPrefs); 117 FakeCurrentWallpaperInfoFactory wallpaperInfoFactory = 118 new FakeCurrentWallpaperInfoFactory(refresher); 119 120 InjectorProvider.setInjector(new TestInjector( 121 new TestUserEventLogger(), 122 new DisplayUtils(mContext, mock(DisplaysProvider.class)), 123 mock(Requester.class), 124 mock(NetworkStatusNotifier.class), 125 mock(PartnerProvider.class), 126 new FakeWallpaperClient(), 127 wallpaperInteractor, 128 mPrefs, 129 mock(WallpaperCategoryWrapper.class), 130 mTestPackageStatusNotifier, 131 wallpaperInfoFactory, 132 refresher 133 )); 134 135 136 mPersister = new DefaultWallpaperPersister(mContext, mManager, mPrefs, changedNotifier, 137 displayUtils, cropper, statusChecker, wallpaperInfoFactory, false); 138 } 139 140 @Test isSeparateLockScreenWallpaperSet_trueIfSet()141 public void isSeparateLockScreenWallpaperSet_trueIfSet() { 142 doReturn(-1).when(mManager).getWallpaperId(FLAG_LOCK); 143 144 assertThat(mPersister.getDefaultWhichWallpaper()).isEqualTo(FLAG_SYSTEM | FLAG_LOCK); 145 } 146 147 @Test isSeparateLockScreenWallpaperSet_falseIfUnset()148 public void isSeparateLockScreenWallpaperSet_falseIfUnset() { 149 doReturn(1).when(mManager).getWallpaperId(FLAG_LOCK); 150 151 assertThat(mPersister.getDefaultWhichWallpaper()).isEqualTo(FLAG_SYSTEM); 152 } 153 154 @Test setBitmapWallpaper_succeeds()155 public void setBitmapWallpaper_succeeds() { 156 TestStaticWallpaperInfo wallpaperInfo = newStaticWallpaperInfo(); 157 prepareWallpaperSetFromInfo(wallpaperInfo); 158 TestSetWallpaperCallback callback = new TestSetWallpaperCallback(); 159 160 mPersister.setIndividualWallpaper(wallpaperInfo, wallpaperInfo.getAsset(mContext), null, 161 1.0f, DEST_BOTH, callback); 162 163 verifyWallpaperSetSuccess(callback); 164 } 165 166 @Test setBitmapWallpaper_setsActionUrl()167 public void setBitmapWallpaper_setsActionUrl() { 168 TestStaticWallpaperInfo wallpaperInfo = newStaticWallpaperInfo(); 169 prepareWallpaperSetFromInfo(wallpaperInfo); 170 TestSetWallpaperCallback callback = new TestSetWallpaperCallback(); 171 172 mPersister.setIndividualWallpaper(wallpaperInfo, wallpaperInfo.getAsset(mContext), null, 173 1.0f, DEST_BOTH, callback); 174 175 verifyWallpaperSetSuccess(callback); 176 assertThat(mPrefs.getHomeWallpaperActionUrl()).isEqualTo(ACTION_URL); 177 assertThat(mPrefs.getLockWallpaperActionUrl()).isEqualTo(ACTION_URL); 178 } 179 180 // Creates a basic test wallpaper info instance. newStaticWallpaperInfo()181 private static TestStaticWallpaperInfo newStaticWallpaperInfo() { 182 List<String> attributions = new ArrayList<>(); 183 attributions.add("Title"); 184 attributions.add("Subtitle 1"); 185 attributions.add("Subtitle 2"); 186 TestStaticWallpaperInfo wallpaperInfo = new TestStaticWallpaperInfo( 187 TestStaticWallpaperInfo.COLOR_DEFAULT); 188 wallpaperInfo.setAttributions(attributions); 189 wallpaperInfo.setCollectionId("collectionStatic"); 190 wallpaperInfo.setWallpaperId("wallpaperStatic"); 191 wallpaperInfo.setActionUrl(ACTION_URL); 192 return wallpaperInfo; 193 } 194 195 // Call this method to prepare for a call to setIndividualWallpaper with non-streamable bitmap. prepareWallpaperSetFromInfo(TestStaticWallpaperInfo wallpaperInfo)196 private void prepareWallpaperSetFromInfo(TestStaticWallpaperInfo wallpaperInfo) { 197 // Retrieve the bitmap to be set by the given WallpaperInfo, and override the return value 198 // from WallpaperManager.getDrawable(). 199 TestAsset asset = (TestAsset) wallpaperInfo.getAsset(mContext); 200 doReturn(new BitmapDrawable(mContext.getResources(), asset.getBitmap())).when(mManager) 201 .getDrawable(); 202 // Override the background executor for AsyncTask to that we can explicitly execute its 203 // tasks - otherwise this will remain in the queue even after main looper idle. 204 ShadowPausedAsyncTask.overrideExecutor(mPausedExecutor); 205 } 206 verifyWallpaperSetSuccess(TestSetWallpaperCallback callback)207 private void verifyWallpaperSetSuccess(TestSetWallpaperCallback callback) { 208 // Execute pending Asset#decodeBitmap; queues SetWallpaperTask background job 209 shadowMainLooper().idle(); 210 // Execute SetWallpaperTask background job; queues onPostExecute on main thread 211 mPausedExecutor.runAll(); 212 // Execute SetWallpaperTask#onPostExecute 213 shadowMainLooper().idle(); 214 215 assertThat(callback.getStatus()).isEqualTo(SetWallpaperStatus.SUCCESS); 216 } 217 218 /** 219 * Simple wallpaper callback to either record success or log on failure. 220 */ 221 static class TestSetWallpaperCallback implements SetWallpaperCallback { 222 enum SetWallpaperStatus { 223 UNCALLED, 224 SUCCESS, 225 FAILURE 226 } 227 SetWallpaperStatus mStatus = SetWallpaperStatus.UNCALLED; 228 @Override onSuccess(WallpaperInfo wallpaperInfo, int destination)229 public void onSuccess(WallpaperInfo wallpaperInfo, int destination) { 230 mStatus = SetWallpaperStatus.SUCCESS; 231 } 232 233 @Override onError(@ullable Throwable throwable)234 public void onError(@Nullable Throwable throwable) { 235 mStatus = SetWallpaperStatus.FAILURE; 236 Log.e(TAG, "Set wallpaper failed", throwable); 237 } 238 getStatus()239 public SetWallpaperStatus getStatus() { 240 return mStatus; 241 } 242 } 243 } 244