1 /* 2 * Copyright (C) 2024 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 17 package com.android.wallpaper.picker.preview.ui.viewmodel 18 19 import android.app.WallpaperInfo 20 import android.content.Context 21 import android.content.pm.ActivityInfo 22 import android.content.pm.PackageManager 23 import android.content.pm.ResolveInfo 24 import android.content.pm.ServiceInfo 25 import android.net.Uri 26 import androidx.test.core.app.ActivityScenario 27 import com.android.wallpaper.effects.Effect 28 import com.android.wallpaper.effects.FakeEffectsController 29 import com.android.wallpaper.module.InjectorProvider 30 import com.android.wallpaper.picker.data.CreativeWallpaperData 31 import com.android.wallpaper.picker.data.DownloadableWallpaperData 32 import com.android.wallpaper.picker.data.WallpaperModel 33 import com.android.wallpaper.picker.preview.PreviewTestActivity 34 import com.android.wallpaper.picker.preview.data.repository.ImageEffectsRepository.EffectStatus 35 import com.android.wallpaper.picker.preview.data.repository.WallpaperPreviewRepository 36 import com.android.wallpaper.picker.preview.data.util.FakeLiveWallpaperDownloader 37 import com.android.wallpaper.picker.preview.domain.interactor.PreviewActionsInteractor 38 import com.android.wallpaper.picker.preview.shared.model.ImageEffectsModel 39 import com.android.wallpaper.picker.preview.shared.model.LiveWallpaperDownloadResultCode 40 import com.android.wallpaper.picker.preview.shared.model.LiveWallpaperDownloadResultModel 41 import com.android.wallpaper.picker.preview.ui.util.LiveWallpaperDeleteUtil 42 import com.android.wallpaper.testing.FakeImageEffectsRepository 43 import com.android.wallpaper.testing.ShadowWallpaperInfo 44 import com.android.wallpaper.testing.TestInjector 45 import com.android.wallpaper.testing.WallpaperModelUtils 46 import com.android.wallpaper.testing.collectLastValue 47 import com.google.common.truth.Truth.assertThat 48 import dagger.hilt.EntryPoint 49 import dagger.hilt.InstallIn 50 import dagger.hilt.android.EntryPointAccessors 51 import dagger.hilt.android.components.ActivityComponent 52 import dagger.hilt.android.qualifiers.ApplicationContext 53 import dagger.hilt.android.testing.HiltAndroidRule 54 import dagger.hilt.android.testing.HiltAndroidTest 55 import javax.inject.Inject 56 import kotlinx.coroutines.Dispatchers 57 import kotlinx.coroutines.ExperimentalCoroutinesApi 58 import kotlinx.coroutines.launch 59 import kotlinx.coroutines.test.TestDispatcher 60 import kotlinx.coroutines.test.runTest 61 import kotlinx.coroutines.test.setMain 62 import org.junit.Before 63 import org.junit.Rule 64 import org.junit.Test 65 import org.junit.runner.RunWith 66 import org.robolectric.RobolectricTestRunner 67 import org.robolectric.Shadows 68 import org.robolectric.annotation.Config 69 70 @HiltAndroidTest 71 @OptIn(ExperimentalCoroutinesApi::class) 72 @RunWith(RobolectricTestRunner::class) 73 @Config(shadows = [ShadowWallpaperInfo::class]) 74 class PreviewActionsViewModelTest { 75 @get:Rule var hiltRule = HiltAndroidRule(this) 76 77 private lateinit var scenario: ActivityScenario<PreviewTestActivity> 78 private lateinit var viewModel: PreviewActionsViewModel 79 private lateinit var wallpaperPreviewRepository: WallpaperPreviewRepository 80 private lateinit var previewActionsInteractor: PreviewActionsInteractor 81 82 @Inject lateinit var testDispatcher: TestDispatcher 83 @Inject @ApplicationContext lateinit var appContext: Context 84 @Inject lateinit var testInjector: TestInjector 85 @Inject lateinit var imageEffectsRepository: FakeImageEffectsRepository 86 @Inject lateinit var liveWallpaperDeleteUtil: LiveWallpaperDeleteUtil 87 @Inject lateinit var liveWallpaperDownloader: FakeLiveWallpaperDownloader 88 89 @Before setUpnull90 fun setUp() { 91 hiltRule.inject() 92 93 InjectorProvider.setInjector(testInjector) 94 Dispatchers.setMain(testDispatcher) 95 96 val activityInfo = 97 ActivityInfo().apply { 98 name = PreviewTestActivity::class.java.name 99 packageName = appContext.packageName 100 } 101 Shadows.shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo) 102 scenario = ActivityScenario.launch(PreviewTestActivity::class.java) 103 scenario.onActivity { setEverything(it) } 104 } 105 106 @EntryPoint 107 @InstallIn(ActivityComponent::class) 108 interface ActivityScopeEntryPoint { previewActionsInteractornull109 fun previewActionsInteractor(): PreviewActionsInteractor 110 111 fun wallpaperPreviewRepository(): WallpaperPreviewRepository 112 } 113 114 private fun setEverything(activity: PreviewTestActivity) { 115 val activityScopeEntryPoint = 116 EntryPointAccessors.fromActivity(activity, ActivityScopeEntryPoint::class.java) 117 previewActionsInteractor = activityScopeEntryPoint.previewActionsInteractor() 118 viewModel = 119 PreviewActionsViewModel(previewActionsInteractor, liveWallpaperDeleteUtil, appContext) 120 121 wallpaperPreviewRepository = activityScopeEntryPoint.wallpaperPreviewRepository() 122 } 123 124 @Test <lambda>null125 fun informationClicked_preparesInformationFloatingSheet() = runTest { 126 val model = WallpaperModelUtils.getStaticWallpaperModel("testId", "testCollection") 127 wallpaperPreviewRepository.setWallpaperModel(model) 128 129 // Simulate click of info button 130 collectLastValue(viewModel.onInformationClicked)()?.invoke() 131 132 val preview = collectLastValue(viewModel.previewFloatingSheetViewModel)() 133 assertThat(preview?.informationFloatingSheetViewModel).isNotNull() 134 } 135 136 @Test <lambda>null137 fun isInformationVisible_checksIfInformationButtonIsVisible() = runTest { 138 val model = WallpaperModelUtils.getStaticWallpaperModel("testId", "testCollection") 139 wallpaperPreviewRepository.setWallpaperModel(model) 140 141 val isInformationButtonVisible = collectLastValue(viewModel.isInformationVisible) 142 assertThat(isInformationButtonVisible()).isTrue() 143 } 144 145 @Test <lambda>null146 fun isInformationVisible_invisibleWhenActionUrlNull() = runTest { 147 val model = WallpaperModelUtils.getStaticWallpaperModel("testId", "testCollection") 148 wallpaperPreviewRepository.setWallpaperModel(model) 149 150 val isInformationButtonVisible = collectLastValue(viewModel.isInformationVisible) 151 152 wallpaperPreviewRepository.setWallpaperModel( 153 WallpaperModelUtils.getStaticWallpaperModel( 154 "testId", 155 "testCollection", 156 actionUrl = null 157 ) 158 ) 159 assertThat(isInformationButtonVisible()).isFalse() 160 } 161 162 @Test <lambda>null163 fun isInformationChecked_checksIfInformationButtonIsChecked() = runTest { 164 val model = WallpaperModelUtils.getStaticWallpaperModel("testId", "testCollection") 165 wallpaperPreviewRepository.setWallpaperModel(model) 166 167 val isInformationButtonChecked = collectLastValue(viewModel.isInformationChecked) 168 assertThat(isInformationButtonChecked()).isFalse() 169 170 collectLastValue(viewModel.onInformationClicked)()?.invoke() 171 172 assertThat(isInformationButtonChecked()).isTrue() 173 } 174 175 @Test <lambda>null176 fun imageEffectSet_preparesImageEffectFloatingSheet() = runTest { 177 val model = WallpaperModelUtils.getStaticWallpaperModel("testId", "testCollection") 178 wallpaperPreviewRepository.setWallpaperModel(model) 179 val effect = 180 Effect(id = 1, title = "test effect", type = FakeEffectsController.Effect.FAKE_EFFECT) 181 imageEffectsRepository.wallpaperEffect.value = effect 182 val imageEffectsModel = ImageEffectsModel(status = EffectStatus.EFFECT_READY) 183 imageEffectsRepository.imageEffectsModel.value = imageEffectsModel 184 185 // Simulate click of effects button 186 collectLastValue(viewModel.onEffectsClicked)()?.invoke() 187 188 val preview = collectLastValue(viewModel.previewFloatingSheetViewModel)() 189 assertThat(preview?.imageEffectFloatingSheetViewModel).isNotNull() 190 } 191 192 @Test <lambda>null193 fun isDownloadVisible_preparesDownloadableWallpaperData() = runTest { 194 val model = getDownloadableWallpaperModel() 195 wallpaperPreviewRepository.setWallpaperModel(model) 196 197 val isDownloadVisible = collectLastValue(viewModel.isDownloadVisible) 198 assertThat(isDownloadVisible()).isTrue() 199 } 200 201 @Test <lambda>null202 fun isDownloadButtonEnabled_trueWhenDownloading() = runTest { 203 val isDownloadButtonEnabled = collectLastValue(viewModel.isDownloadButtonEnabled) 204 205 // verify the download button is disabled during a download 206 backgroundScope.launch { previewActionsInteractor.downloadWallpaper() } 207 assertThat(isDownloadButtonEnabled()).isFalse() 208 209 val model = getDownloadableWallpaperModel() 210 211 wallpaperPreviewRepository.setWallpaperModel(model) 212 liveWallpaperDownloader.setWallpaperDownloadResult( 213 LiveWallpaperDownloadResultModel(LiveWallpaperDownloadResultCode.FAIL, null) 214 ) 215 // verify the download button is enabled after downloading is complete 216 assertThat(isDownloadButtonEnabled()).isTrue() 217 } 218 219 @Test <lambda>null220 fun isDeleteVisible_whenWallpaperCanBeDeleted() = runTest { 221 val resolveInfo = 222 ResolveInfo().apply { 223 serviceInfo = ServiceInfo() 224 serviceInfo.packageName = "com.google.android.apps.wallpaper.nexus" 225 serviceInfo.splitName = "wallpaper_cities_ny" 226 serviceInfo.name = "NewYorkWallpaper" 227 serviceInfo.flags = PackageManager.GET_META_DATA 228 } 229 val wallpaperInfo = WallpaperInfo(appContext, resolveInfo) 230 val liveWallpaperModel = 231 WallpaperModelUtils.getLiveWallpaperModel( 232 wallpaperId = "testWallpaperId", 233 collectionId = "testCollection", 234 systemWallpaperInfo = wallpaperInfo, 235 isApplied = false, 236 creativeWallpaperData = 237 CreativeWallpaperData( 238 configPreviewUri = null, 239 cleanPreviewUri = null, 240 deleteUri = Uri.parse("https://www.deleteme.com"), 241 thumbnailUri = null, 242 shareUri = null, 243 author = "fake", 244 description = "fake", 245 contentDescription = null, 246 isCurrent = false, 247 creativeWallpaperEffectsData = null, 248 ), 249 ) 250 wallpaperPreviewRepository.setWallpaperModel(liveWallpaperModel) 251 252 val isDeleteVisible = collectLastValue(viewModel.isDeleteVisible) 253 assertThat(isDeleteVisible()).isTrue() 254 } 255 getDownloadableWallpaperModelnull256 private fun getDownloadableWallpaperModel(): WallpaperModel.StaticWallpaperModel { 257 val wallpaperInfo = 258 WallpaperInfo( 259 appContext, 260 ResolveInfo().apply { 261 serviceInfo = ServiceInfo() 262 serviceInfo.packageName = "com.google.android.apps.wallpaper.nexus" 263 serviceInfo.splitName = "fake" 264 serviceInfo.name = "FakeWallpaper" 265 serviceInfo.flags = PackageManager.GET_META_DATA 266 } 267 ) 268 val downladableWallpaperDataTest = 269 DownloadableWallpaperData( 270 groupName = "testGroupName", 271 systemWallpaperInfo = wallpaperInfo, 272 isTitleVisible = false, 273 isApplied = false 274 ) 275 val model = 276 WallpaperModelUtils.getStaticWallpaperModel( 277 wallpaperId = "testId", 278 collectionId = "testCollection", 279 downloadableWallpaperData = downladableWallpaperDataTest 280 ) 281 return model 282 } 283 } 284