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 65 var success = true 66 // TODO: Only persist assets when the wallpaper is applied. 67 success = success and WallpaperFileUtils.exportBitmap( 68 context, 69 WallpaperFileUtils.FG_FILE_NAME, 70 foreground, 71 ) 72 success = success and WallpaperFileUtils.exportBitmap( 73 context, 74 WallpaperFileUtils.BG_FILE_NAME, 75 background, 76 ) 77 if (!success) { 78 Log.e(TAG, "Failed to export assets during wallpaper generation") 79 return 80 } 81 82 // We always respect the new weather. 83 val weather = wallpaperFileModel.weatherEffect 84 if (weather != null) WallpaperFileUtils.exportLastKnownWeather(weather, context) 85 86 _wallpaperImage.value = WallpaperImageModel( 87 foreground, 88 background, 89 weather 90 ) 91 } catch (e: RuntimeException) { 92 Log.e(TAG, "Unable to load wallpaper: ", e) 93 } catch (e: OutOfMemoryError) { 94 Log.e(TAG, "Unable to load wallpaper: ", e) 95 } 96 } 97 98 /** 99 * Loads wallpaper from the persisted files in local storage. 100 * This assumes wallpaper assets exist in local storage under fixed names. 101 */ 102 suspend fun loadWallpaperFromLocalStorage() { 103 try { 104 val fgBitmap = WallpaperFileUtils.importBitmapFromLocalStorage( 105 WallpaperFileUtils.FG_FILE_NAME, context 106 ) 107 val bgBitmap = WallpaperFileUtils.importBitmapFromLocalStorage( 108 WallpaperFileUtils.BG_FILE_NAME, context 109 ) 110 if (fgBitmap == null || bgBitmap == null) { 111 Log.w(TAG, "Cannot load wallpaper from local storage.") 112 return 113 } 114 115 val weatherEffect = WallpaperFileUtils.importLastKnownWeather(context) 116 117 _wallpaperImage.value = WallpaperImageModel( 118 fgBitmap, 119 bgBitmap, 120 weatherEffect, 121 ) 122 } catch (e: RuntimeException) { 123 Log.e(TAG, "Unable to load wallpaper: ", e) 124 } catch (e: OutOfMemoryError) { 125 Log.e(TAG, "Unable to load wallpaper: ", e) 126 null 127 } 128 } 129 130 suspend fun saveWallpaper() { 131 val foreground = _wallpaperImage.value?.foreground 132 val background = _wallpaperImage.value?.background 133 134 var success = true 135 success = success and (foreground?.let { 136 WallpaperFileUtils.exportBitmap( 137 context, 138 WallpaperFileUtils.FG_FILE_NAME, 139 it, 140 ) 141 } == true) 142 success = success and (background?.let { 143 WallpaperFileUtils.exportBitmap( 144 context, 145 WallpaperFileUtils.BG_FILE_NAME, 146 it, 147 ) 148 } == true) 149 if (success) { 150 Log.d(TAG, "Successfully save wallpaper") 151 } else { 152 Log.e(TAG, "Failed to save wallpaper") 153 } 154 } 155 156 companion object { 157 private const val TAG = "WeatherEffectsRepository" 158 } 159 } 160