Closes #9530: Don't crash on failed avatar fetches
parent
fd263d8329
commit
f76acc5db1
|
@ -5,20 +5,23 @@
|
|||
package org.mozilla.fenix.ext
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.util.Patterns
|
||||
import android.webkit.URLUtil
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.concept.fetch.Client
|
||||
import mozilla.components.concept.fetch.Request
|
||||
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
||||
import mozilla.components.lib.publicsuffixlist.ext.urlToTrimmedHost
|
||||
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||
import java.io.IOException
|
||||
import java.net.IDN
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
import java.util.Locale
|
||||
|
||||
const val FILE_PREFIX = "file://"
|
||||
|
@ -113,17 +116,23 @@ fun String.simplifiedUrl(): String {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets a rounded drawable from a URL if possible, else null. Must be called off main thread.
|
||||
* Gets a rounded drawable from a URL if possible, else null.
|
||||
*/
|
||||
fun String.decodeUrlToRoundedDrawable(context: Context): RoundedBitmapDrawable? {
|
||||
val avatarUrl = try {
|
||||
URL(this)
|
||||
} catch (e: MalformedURLException) {
|
||||
return null
|
||||
suspend fun String.toRoundedDrawable(context: Context, client: Client) = bitmapForUrl(this, client)?.let { bitmap ->
|
||||
RoundedBitmapDrawableFactory.create(context.resources, bitmap).also {
|
||||
it.isCircular = true
|
||||
it.setAntiAlias(true)
|
||||
}
|
||||
val bitmap = BitmapFactory.decodeStream(avatarUrl.openConnection().getInputStream())
|
||||
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(context.resources, bitmap)
|
||||
roundedBitmapDrawable.isCircular = true
|
||||
roundedBitmapDrawable.setAntiAlias(true)
|
||||
return roundedBitmapDrawable
|
||||
}
|
||||
|
||||
suspend fun bitmapForUrl(url: String, client: Client): Bitmap? = withContext(Dispatchers.IO) {
|
||||
// TODO cache this image, see https://github.com/mozilla-mobile/fenix/issues/9531
|
||||
// Code below will cache it in Gecko's cache, which ensures that as long as we've fetched it once,
|
||||
// we will be able to display this avatar as long as the cache isn't purged (e.g. via 'clear user data').
|
||||
val body = try {
|
||||
client.fetch(Request(url, useCaches = true)).body
|
||||
} catch (e: IOException) {
|
||||
return@withContext null
|
||||
}
|
||||
body.useStream { BitmapFactory.decodeStream(it) }
|
||||
}
|
||||
|
|
|
@ -22,11 +22,9 @@ import androidx.preference.PreferenceCategory
|
|||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.concept.sync.AccountObserver
|
||||
import mozilla.components.concept.sync.AuthType
|
||||
import mozilla.components.concept.sync.OAuthAccount
|
||||
|
@ -39,7 +37,7 @@ import org.mozilla.fenix.R
|
|||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.ext.application
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.decodeUrlToRoundedDrawable
|
||||
import org.mozilla.fenix.ext.toRoundedDrawable
|
||||
import org.mozilla.fenix.ext.getPreferenceKey
|
||||
import org.mozilla.fenix.ext.metrics
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
|
@ -375,16 +373,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
if (account != null && !accountManager.accountNeedsReauth()) {
|
||||
preferenceSignIn?.isVisible = false
|
||||
|
||||
profile?.avatar?.url?.let {
|
||||
lifecycleScope.launch(IO) {
|
||||
val roundedDrawable = it.decodeUrlToRoundedDrawable(context)
|
||||
withContext(Main) {
|
||||
preferenceFirefoxAccount?.icon =
|
||||
roundedDrawable ?: AppCompatResources.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_account
|
||||
)
|
||||
}
|
||||
profile?.avatar?.url?.let { avatarUrl ->
|
||||
lifecycleScope.launch(Main) {
|
||||
val roundedDrawable = avatarUrl.toRoundedDrawable(context, requireComponents.core.client)
|
||||
preferenceFirefoxAccount?.icon =
|
||||
roundedDrawable ?: AppCompatResources.getDrawable(context, R.drawable.ic_account)
|
||||
}
|
||||
}
|
||||
preferenceSignIn?.onPreferenceClickListener = null
|
||||
|
|
Loading…
Reference in New Issue