• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.graphics.Bitmap
21 import android.graphics.BitmapFactory
22 import android.util.Log
23 import kotlinx.coroutines.CoroutineDispatcher
24 import kotlinx.coroutines.Dispatchers
25 import kotlinx.coroutines.withContext
26 
27 object WallpaperFileUtils {
28     /**
29      * Exports the [bitmap] to an image file in local storage.
30      * This method may take several seconds to complete, so it should be called from
31      * a background [dispatcher].
32      *
33      * @param context the [Context] of the caller
34      * @param bitmap the source to be exported
35      * @param dispatcher the dispatcher to run within.
36      * @return `true` when exported successfully
37      */
exportnull38     suspend fun export(
39         context: Context,
40         fileName: String,
41         bitmap: Bitmap,
42         dispatcher: CoroutineDispatcher = Dispatchers.IO,
43     ): Boolean {
44         val protectedContext = asProtectedContext(context)
45         return try {
46             withContext(dispatcher) {
47                 var success: Boolean
48                 protectedContext
49                     .openFileOutput(fileName, Context.MODE_PRIVATE)
50                     .use {
51                         success = bitmap.compress(
52                             Bitmap.CompressFormat.PNG,
53                             /* quality = */ 100,
54                             it,
55                         )
56                         if (!success) {
57                             Log.e(TAG, "Failed to write the bitmap to local storage")
58                         } else {
59                             Log.i(TAG, "Wrote bitmap to local storage. filename: $fileName")
60                         }
61                     }
62                 success
63             }
64         } catch (e: Exception) {
65             Log.e(TAG, "Failed to export", e)
66             false
67         }
68     }
69 
70     /**
71      * Imports the bitmap from an absolute path. This method may take several seconds to complete,
72      * so it should be called from a background [dispatcher].
73      *
74      * @param absolutePath the absolute file path of the bitmap to be imported.
75      * @param dispatcher the dispatcher to run within.
76      * @return the imported wallpaper bitmap, or `null` if importing failed.
77      */
importBitmapFromAbsolutePathnull78     suspend fun importBitmapFromAbsolutePath(
79         absolutePath: String,
80         dispatcher: CoroutineDispatcher = Dispatchers.IO,
81     ): Bitmap? {
82         return try {
83             withContext(dispatcher) {
84                 val bitmap = BitmapFactory.decodeFile(absolutePath)
85                 if (bitmap == null) {
86                     Log.e(TAG, "Failed to decode the bitmap")
87                 }
88                 bitmap
89             }
90         } catch (e: Exception) {
91             Log.e(TAG, "Failed to import the image", e)
92             null
93         }
94     }
95 
96     /**
97      * Imports the bitmap from local storage. This method may take several seconds to complete,
98      * so it should be called from a background [dispatcher].
99      *
100      * @param fileName name of the bitmap file in local storage.
101      * @param dispatcher the dispatcher to run within.
102      * @return the imported wallpaper bitmap, or `null` if importing failed.
103      */
importBitmapFromLocalStoragenull104     suspend fun importBitmapFromLocalStorage(
105         fileName: String,
106         context: Context,
107         dispatcher: CoroutineDispatcher = Dispatchers.IO,
108     ): Bitmap? {
109         return try {
110             withContext(dispatcher) {
111                 val protectedContext = asProtectedContext(context)
112                 val inputStream = protectedContext.openFileInput(fileName)
113                 val bitmap = BitmapFactory.decodeStream(inputStream)
114                 if (bitmap == null) {
115                     Log.e(TAG, "Failed to decode the bitmap")
116                 }
117                 bitmap
118             }
119         } catch (e: Exception) {
120             Log.e(TAG, "Failed to import the image", e)
121             null
122         }
123     }
124 
asProtectedContextnull125     private fun asProtectedContext(context: Context): Context {
126         return if (context.isDeviceProtectedStorage) {
127             context
128         } else {
129             context.createDeviceProtectedStorageContext()
130         }
131     }
132 
133     private const val TAG = "WallpaperFileUtils"
134     const val FG_FILE_NAME = "fg_image"
135     const val BG_FILE_NAME = "bg_image"
136 }
137