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