@@ -20,11 +20,14 @@ import android.content.Context
20
20
import android.graphics.Bitmap
21
21
import android.graphics.BitmapFactory
22
22
import com.duckduckgo.app.global.file.FileDeleter
23
+ import com.duckduckgo.app.pixels.remoteconfig.AndroidBrowserConfigFeature
23
24
import com.duckduckgo.common.utils.DispatcherProvider
24
25
import com.duckduckgo.common.utils.sha256
25
26
import java.io.File
26
27
import java.io.FileOutputStream
27
28
import kotlinx.coroutines.NonCancellable
29
+ import kotlinx.coroutines.sync.Mutex
30
+ import kotlinx.coroutines.sync.withLock
28
31
import kotlinx.coroutines.withContext
29
32
import timber.log.Timber
30
33
@@ -62,8 +65,11 @@ class FileBasedFaviconPersister(
62
65
val context : Context ,
63
66
private val fileDeleter : FileDeleter ,
64
67
private val dispatcherProvider : DispatcherProvider ,
68
+ private val androidBrowserConfigFeature : AndroidBrowserConfigFeature ,
65
69
) : FaviconPersister {
66
70
71
+ val mutex = Mutex ()
72
+
67
73
override suspend fun deleteAll (directory : String ) {
68
74
fileDeleter.deleteDirectory(faviconDirectory(directory))
69
75
}
@@ -100,7 +106,11 @@ class FileBasedFaviconPersister(
100
106
domain : String ,
101
107
): File ? {
102
108
return withContext(dispatcherProvider.io() + NonCancellable ) {
103
- writeToDisk(directory, subFolder, bitmap, domain)
109
+ if (androidBrowserConfigFeature.storeFaviconSuspend().isEnabled()) {
110
+ writeToDiskAsync(directory, subFolder, bitmap, domain)
111
+ } else {
112
+ writeToDisk(directory, subFolder, bitmap, domain)
113
+ }
104
114
}
105
115
}
106
116
@@ -181,6 +191,42 @@ class FileBasedFaviconPersister(
181
191
}
182
192
}
183
193
194
+ private suspend fun writeToDiskAsync (
195
+ directory : String ,
196
+ subFolder : String ,
197
+ bitmap : Bitmap ,
198
+ domain : String ,
199
+ ): File ? {
200
+ mutex.withLock {
201
+ val existingFile = fileForFavicon(directory, subFolder, domain)
202
+
203
+ if (existingFile.exists()) {
204
+ Timber .i(" Favicon favicon exists for $domain in $subFolder " )
205
+ val existingFavicon = BitmapFactory .decodeFile(existingFile.absolutePath)
206
+
207
+ existingFavicon?.let {
208
+ if (it.width > bitmap.width) {
209
+ return null // Stored file has better quality
210
+ }
211
+ }
212
+ }
213
+
214
+ val faviconFile = prepareDestinationFile(directory, subFolder, domain)
215
+ runCatching {
216
+ FileOutputStream (faviconFile).use { outputStream ->
217
+ bitmap.compress(Bitmap .CompressFormat .PNG , 100 , outputStream)
218
+ outputStream.flush()
219
+ }
220
+ }
221
+
222
+ return if (faviconFile.exists()) {
223
+ faviconFile
224
+ } else {
225
+ null
226
+ }
227
+ }
228
+ }
229
+
184
230
@Synchronized
185
231
private fun writeBytesToFile (
186
232
file : File ,
0 commit comments