1 /*
<lambda>null2  * 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 
17 package com.google.android.wallpaper.weathereffects.data.repository
18 
19 import android.content.Context
20 import android.util.Log
21 import com.google.android.wallpaper.weathereffects.shared.model.WallpaperFileModel
22 import com.google.android.wallpaper.weathereffects.shared.model.WallpaperImageModel
23 import javax.inject.Inject
24 import javax.inject.Singleton
25 import kotlinx.coroutines.flow.MutableStateFlow
26 import kotlinx.coroutines.flow.StateFlow
27 import kotlinx.coroutines.flow.asStateFlow
28 
29 @Singleton
30 class WeatherEffectsRepository @Inject constructor(
31     private val context: Context,
32 ) {
33     private val _wallpaperImage = MutableStateFlow<WallpaperImageModel?>(null)
34     val wallpaperImage: StateFlow<WallpaperImageModel?>  = _wallpaperImage.asStateFlow()
35 
36     /**
37      * Generates or updates a wallpaper from the provided [wallpaperFileModel].
38      */
39     suspend fun updateWallpaper(wallpaperFileModel: WallpaperFileModel) {
40         try {
41             // Use the existing images if the foreground and background are not supplied.
42             var fgBitmap = _wallpaperImage.value?.foreground
43             var bgBitmap = _wallpaperImage.value?.background
44 
45             wallpaperFileModel.foregroundAbsolutePath?.let {
46                 WallpaperFileUtils.importBitmapFromAbsolutePath(it)?.let { newFg ->
47                     fgBitmap = newFg
48                 }
49             }
50 
51             wallpaperFileModel.backgroundAbsolutePath?.let {
52                 WallpaperFileUtils.importBitmapFromAbsolutePath(it)?.let { newBg ->
53                     bgBitmap = newBg
54                 }
55             }
56 
57             if (fgBitmap == null || bgBitmap == null) {
58                 Log.w(TAG, "Cannot update wallpaper. asset: $wallpaperFileModel")
59                 return
60             }
61 
62             val foreground = fgBitmap!!
63             val background = bgBitmap!!
64             _wallpaperImage.value = WallpaperImageModel(
65                 foreground,
66                 background,
67                 wallpaperFileModel.weatherEffect,
68             )
69         } catch (e: RuntimeException) {
70             Log.e(TAG, "Unable to load wallpaper: ", e)
71         } catch (e: OutOfMemoryError) {
72             Log.e(TAG, "Unable to load wallpaper: ", e)
73         }
74     }
75 
76     /**
77      * Loads wallpaper from the persisted files in local storage.
78      * This assumes wallpaper assets exist in local storage under fixed names.
79      */
80     suspend fun loadWallpaperFromLocalStorage() {
81         try {
82             val fgBitmap = WallpaperFileUtils.importBitmapFromLocalStorage(
83                 WallpaperFileUtils.FG_FILE_NAME, context
84             )
85             val bgBitmap = WallpaperFileUtils.importBitmapFromLocalStorage(
86                 WallpaperFileUtils.BG_FILE_NAME, context
87             )
88             if (fgBitmap == null || bgBitmap == null) {
89                 Log.w(TAG, "Cannot load wallpaper from local storage.")
90                 return
91             }
92             _wallpaperImage.value = WallpaperImageModel(
93                 fgBitmap,
94                 bgBitmap,
95                 // TODO: Add new API to change weather type dynamically
96             )
97         } catch (e: RuntimeException) {
98             Log.e(TAG, "Unable to load wallpaper: ", e)
99         } catch (e: OutOfMemoryError) {
100             Log.e(TAG, "Unable to load wallpaper: ", e)
101         }
102     }
103 
104     suspend fun saveWallpaper() {
105         val foreground = _wallpaperImage.value?.foreground
106         val background = _wallpaperImage.value?.background
107 
108         var success = true
109         success = success and (foreground?.let {
110             WallpaperFileUtils.export(
111                 context,
112                 WallpaperFileUtils.FG_FILE_NAME,
113                 it,
114             )
115         } == true)
116         success = success and (background?.let {
117             WallpaperFileUtils.export(
118                 context,
119                 WallpaperFileUtils.BG_FILE_NAME,
120                 it,
121             )
122         } == true)
123         if (success) {
124             Log.d(TAG, "Successfully save wallpaper")
125         } else {
126             Log.e(TAG, "Failed to save wallpaper")
127         }
128     }
129 
130     companion object {
131         private const val TAG = "WeatherEffectsRepository"
132     }
133 }
134