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