From 60d9bcec185a924b8899d897d741ee86d15e5e00 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Thu, 27 Jan 2022 11:15:05 -0500 Subject: [PATCH] [fenix] For https://github.com/mozilla-mobile/fenix/issues/23432 - Use the imageUrl as the favicon for a provided top site --- .../main/java/org/mozilla/fenix/ext/Client.kt | 29 ++++++++++ .../main/java/org/mozilla/fenix/ext/String.kt | 18 ------ .../home/topsites/TopSiteItemViewHolder.kt | 56 ++++++++++++------- .../fenix/settings/account/AccountUiView.kt | 2 +- 4 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/ext/Client.kt diff --git a/app/src/main/java/org/mozilla/fenix/ext/Client.kt b/app/src/main/java/org/mozilla/fenix/ext/Client.kt new file mode 100644 index 000000000..99d3e79e2 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/ext/Client.kt @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ext + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import mozilla.components.concept.fetch.Client +import mozilla.components.concept.fetch.Request +import java.io.IOException + +/** + * Given an image [url], fetches and returns a [Bitmap] if possible, otherwise null. + * + * @param url The image URL to fetch from. + */ +suspend fun Client.bitmapForUrl(url: String): Bitmap? = withContext(Dispatchers.IO) { + // 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 { + fetch(Request(url, useCaches = true)).body + } catch (e: IOException) { + return@withContext null + } + body.useStream { BitmapFactory.decodeStream(it) } +} diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index c9afbd8b3..c01e4db5a 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -4,20 +4,13 @@ package org.mozilla.fenix.ext -import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.net.Uri import android.text.Editable import android.util.Patterns import android.webkit.URLUtil import androidx.core.net.toUri -import kotlinx.coroutines.Dispatchers -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.support.ktx.android.net.hostWithoutCommonPrefixes -import java.io.IOException import java.net.IDN import java.util.Locale @@ -110,14 +103,3 @@ fun String.simplifiedUrl(): String { * Returns an [Editable] for the provided string. */ fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this) - -suspend fun bitmapForUrl(url: String, client: Client): Bitmap? = withContext(Dispatchers.IO) { - // 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) } -} diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt index 2a7f385d5..45a40a24d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt @@ -10,12 +10,18 @@ import android.view.MotionEvent import android.view.View import android.widget.PopupWindow import androidx.appcompat.content.res.AppCompatResources.getDrawable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import mozilla.components.browser.menu.BrowserMenuBuilder import mozilla.components.browser.menu.item.SimpleBrowserMenuItem import mozilla.components.feature.top.sites.TopSite import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.databinding.TopSiteItemBinding +import org.mozilla.fenix.ext.bitmapForUrl import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor @@ -72,27 +78,37 @@ class TopSiteItemViewHolder( binding.topSiteTitle.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null) } - when (topSite.url) { - SupportUtils.POCKET_TRENDING_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_pocket)) - } - SupportUtils.BAIDU_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_baidu)) - } - SupportUtils.JD_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_jd)) - } - SupportUtils.PDD_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_pdd)) - } - SupportUtils.TC_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_tc)) - } - SupportUtils.MEITUAN_URL -> { - binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_meituan)) + if (topSite is TopSite.Provided) { + CoroutineScope(IO).launch { + itemView.context.components.core.client.bitmapForUrl(topSite.imageUrl)?.let { bitmap -> + withContext(Main) { + binding.faviconImage.setImageBitmap(bitmap) + } + } } - else -> { - itemView.context.components.core.icons.loadIntoView(binding.faviconImage, topSite.url) + } else { + when (topSite.url) { + SupportUtils.POCKET_TRENDING_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_pocket)) + } + SupportUtils.BAIDU_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_baidu)) + } + SupportUtils.JD_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_jd)) + } + SupportUtils.PDD_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_pdd)) + } + SupportUtils.TC_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_tc)) + } + SupportUtils.MEITUAN_URL -> { + binding.faviconImage.setImageDrawable(getDrawable(itemView.context, R.drawable.ic_meituan)) + } + else -> { + itemView.context.components.core.icons.loadIntoView(binding.faviconImage, topSite.url) + } } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt b/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt index 94464b035..c204fee61 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt @@ -114,7 +114,7 @@ class AccountUiView( private suspend fun toRoundedDrawable( url: String, context: Context - ) = bitmapForUrl(url, httpClient)?.let { bitmap -> + ) = httpClient.bitmapForUrl(url)?.let { bitmap -> RoundedBitmapDrawableFactory.create(context.resources, bitmap).apply { isCircular = true setAntiAlias(true)