Closes #9530: Don't crash on failed avatar fetches

fennec/beta
Grisha Kruglov 4 years ago committed by Sebastian Kaspari
parent eb5cdcd7ec
commit 12f4071e33

@ -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) }
}

@ -20,11 +20,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
@ -37,7 +35,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
@ -347,16 +345,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…
Cancel
Save