Commit edd982e7 authored by Sandor Molnar's avatar Sandor Molnar Committed by smolnar@mozilla.com
Browse files

Revert "Bug 1966117 - Fix search icons fetched from client...

Revert "Bug 1966117 - Fix search icons fetched from client r=android-reviewers,harrisono" for causing fenix ui-test failures

This reverts commit 449d6036.
parent fbcd9c5c
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@

package mozilla.components.feature.search

import mozilla.appservices.remotesettings.RemoteSettingsClient
import mozilla.appservices.remotesettings.RemoteSettingsException
import mozilla.appservices.remotesettings.RemoteSettingsRecord
import mozilla.components.support.base.log.logger.Logger
@@ -31,10 +30,10 @@ class RemoteSettingsRepository private constructor() {
        fun fetchRemoteResponse(
            service: RemoteSettingsService,
            collectionName: String,
            client: RemoteSettingsClient? = service.remoteSettingsService.makeClient(collectionName),
        ): List<RemoteSettingsRecord>? {
            return try {
                return client?.getRecords()
                val client = service.remoteSettingsService.makeClient(collectionName)
                return client.getRecords()
            } catch (e: RemoteSettingsException) {
                logger.error("Remote Settings Exception", e)
                emptyList()
+4 −17
Original line number Diff line number Diff line
@@ -4,8 +4,6 @@

package mozilla.components.feature.search.icons

import mozilla.appservices.remotesettings.RemoteSettingsClient
import mozilla.appservices.remotesettings.RemoteSettingsRecord
import mozilla.components.feature.search.RemoteSettingsRepository
import mozilla.components.support.remotesettings.RemoteSettingsService

@@ -14,9 +12,8 @@ internal const val SEARCH_CONFIG_ICONS_COLLECTION_NAME = "search-config-icons"
/**
 * Service for updating search configuration icons from Remote Settings.
 */
class SearchConfigIconsUpdateService(
    private val client: RemoteSettingsClient?,
) {
class SearchConfigIconsUpdateService {
    private val parser = SearchConfigIconsParser()

    /**
     * Fetches the latest search config icons.
@@ -24,20 +21,10 @@ class SearchConfigIconsUpdateService(
     * @param service The [RemoteSettingsService] to fetch data from.
     * @return List of [SearchConfigIconsModel] objects.
     */
    fun fetchIconsRecords(service: RemoteSettingsService): List<RemoteSettingsRecord> {
    fun fetchIcons(service: RemoteSettingsService): List<SearchConfigIconsModel> {
        return RemoteSettingsRepository.fetchRemoteResponse(
            service = service,
            collectionName = SEARCH_CONFIG_ICONS_COLLECTION_NAME,
            client = client,
        ) ?: emptyList()
    }

    /**
     * Fetches the latest search config icons.
     *
     * @param record The [RemoteSettingsRecord] who's attachment is to be fetched.
=     */
    fun fetchIconAttachment(record: RemoteSettingsRecord): ByteArray? {
        return client?.getAttachment(record)
        )?.mapNotNull(parser::parseRecord) ?: emptyList()
    }
}
+1 −8
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import mozilla.appservices.remotesettings.RemoteSettingsClient
import mozilla.components.browser.state.action.BrowserAction
import mozilla.components.browser.state.action.SearchAction
import mozilla.components.browser.state.search.RegionState
@@ -39,8 +38,6 @@ data class SearchExtraParams(
    val channelIdParam: String,
)

internal const val SEARCH_CONFIG_ICONS_COLLECTION_NAME = "search-config-icons"

/**
 * [Middleware] implementation for loading and saving [SearchEngine]s whenever the state changes.
 *
@@ -71,12 +68,8 @@ class SearchMiddleware(
) : Middleware<BrowserState, BrowserAction> {
    private val logger = Logger("SearchMiddleware")
    private val scope = CoroutineScope(ioDispatcher)
    private val client: RemoteSettingsClient? =
        searchEngineSelectorConfig?.service?.remoteSettingsService?.makeClient(SEARCH_CONFIG_ICONS_COLLECTION_NAME)
    private val searchEngineSelectorRepository: SearchEngineRepository? =
        searchEngineSelectorConfig?.let {
                SearchEngineSelectorRepository(it, client)
        }
        searchEngineSelectorConfig?.let { SearchEngineSelectorRepository(it) }

    override fun invoke(
        context: MiddlewareContext<BrowserState, BrowserAction>,
+18 −16
Original line number Diff line number Diff line
@@ -16,14 +16,17 @@ import mozilla.appservices.search.SearchUrlParam
import mozilla.components.browser.icons.decoder.ICOIconDecoder
import mozilla.components.browser.icons.decoder.SvgIconDecoder
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.feature.search.icons.AttachmentModel
import mozilla.components.feature.search.middleware.SearchExtraParams
import mozilla.components.support.images.DesiredSize
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.net.URL
import java.nio.charset.StandardCharsets

internal const val URL_TYPE_SUGGEST_JSON = "application/x-suggestions+json"
@@ -34,6 +37,7 @@ internal const val IMAGE_URI_PREFIX = "data:image/png;base64,"
internal const val GOOGLE_ID = "google"
private const val TARGET_SIZE = 32
private const val MAX_SIZE = 32
private const val URL_PREFIX = "https://firefox-settings-attachments.cdn.mozilla.net/"

// List of general search engine ids, taken from
// https://searchfox.org/mozilla-central/rev/ef0aa879e94534ffd067a3748d034540a9fc10b0/toolkit/components/search/SearchUtils.sys.mjs#200
@@ -263,18 +267,19 @@ internal class SearchEngineReader(
    @Throws(IllegalArgumentException::class)
    fun loadStreamAPI(
        engineDefinition: SearchEngineDefinition,
        attachmentModel: ByteArray?,
        mimetype: String,
        attachmentModel: AttachmentModel,
        iconsURLPrefix: String = URL_PREFIX,
    ): SearchEngine {
        require(engineDefinition.name.isNotBlank()) { "Search engine name cannot be empty" }
        require(engineDefinition.charset.isNotBlank()) { "Search engine charset cannot be empty" }
        require(attachmentModel.location.isNotBlank()) { "Search engine icon location cannot be empty" }
        require(engineDefinition.identifier.isNotBlank()) { "Search engine identifier cannot be empty" }
        val builder = SearchEngineBuilder(type, engineDefinition.identifier)
        builder.name = engineDefinition.name
        builder.inputEncoding = engineDefinition.charset
        builder.isGeneral = engineDefinition.classification == SearchEngineClassification.GENERAL
        readUrlAPI(engineDefinition, builder)
        readImageAPI(attachmentModel, mimetype, builder)
        readImageAPI(iconsURLPrefix + attachmentModel.location, attachmentModel.mimetype, builder)

        return builder.toSearchEngine()
    }
@@ -357,29 +362,26 @@ internal class SearchEngineReader(
    }

    @Throws(IllegalArgumentException::class, IllegalStateException::class)
    private fun readImageAPI(attachmentModel: ByteArray?, mimetype: String, builder: SearchEngineBuilder) {
        if (attachmentModel == null) {
            throw IllegalStateException("Failed to decode image for mimetype: $mimetype")
        }
    private fun readImageAPI(iconUri: String, mimetype: String, builder: SearchEngineBuilder) {
        val allowedTypes = setOf("image/jpeg", "image/png", "image/x-icon", "image/svg+xml")
        require(mimetype in allowedTypes) { "Unsupported image type: $mimetype" }
        val raw: ByteArray
        try {
            raw = URL(iconUri).openStream().use { it.readBytes() }
        } catch (e: FileNotFoundException) {
            throw IllegalArgumentException("Failed to read image from location: $iconUri")
        }
        val bitmap = when (mimetype) {
            "image/svg+xml" -> {
                val decoder = SvgIconDecoder()
                decoder.decode(
                    attachmentModel,
                    DesiredSize(TARGET_SIZE, TARGET_SIZE, MAX_SIZE, 2.0f),
                )
                decoder.decode(raw, DesiredSize(TARGET_SIZE, TARGET_SIZE, MAX_SIZE, 2.0f))
            }
            "image/x-icon" -> {
                val decoder = ICOIconDecoder()
                decoder.decode(
                    attachmentModel,
                    DesiredSize(TARGET_SIZE, TARGET_SIZE, MAX_SIZE, 2.0f),
                )
                decoder.decode(raw, DesiredSize(TARGET_SIZE, TARGET_SIZE, MAX_SIZE, 2.0f))
            }
            else -> {
                BitmapFactory.decodeByteArray(attachmentModel, 0, attachmentModel.size) ?: null
                BitmapFactory.decodeByteArray(raw, 0, raw.size) ?: null
            }
        }
        if (bitmap == null) {
+13 −18
Original line number Diff line number Diff line
@@ -4,8 +4,6 @@

package mozilla.components.feature.search.storage

import mozilla.appservices.remotesettings.RemoteSettingsClient
import mozilla.appservices.remotesettings.RemoteSettingsRecord
import mozilla.appservices.search.RefinedSearchConfig
import mozilla.appservices.search.SearchApiException
import mozilla.appservices.search.SearchUserEnvironment
@@ -15,7 +13,8 @@ import mozilla.components.feature.search.SearchApplicationName
import mozilla.components.feature.search.SearchDeviceType
import mozilla.components.feature.search.SearchEngineSelector
import mozilla.components.feature.search.SearchUpdateChannel
import mozilla.components.feature.search.icons.SearchConfigIconsParser
import mozilla.components.feature.search.icons.AttachmentModel
import mozilla.components.feature.search.icons.SearchConfigIconsModel
import mozilla.components.feature.search.icons.SearchConfigIconsUpdateService
import mozilla.components.feature.search.into
import mozilla.components.feature.search.middleware.SearchExtraParams
@@ -33,13 +32,11 @@ import kotlin.coroutines.CoroutineContext
 */
class SearchEngineSelectorRepository(
    private val searchEngineSelectorConfig: SearchEngineSelectorConfig,
    client: RemoteSettingsClient?,
) : SearchMiddleware.SearchEngineRepository {

    private val searchConfigIconsUpdateService: SearchConfigIconsUpdateService = SearchConfigIconsUpdateService(client)
    private val searchConfigIconsUpdateService: SearchConfigIconsUpdateService = SearchConfigIconsUpdateService()
    private val reader: SearchEngineReader = SearchEngineReader(type = SearchEngine.Type.BUNDLED)
    private val logger = Logger("SearchEngineSelectorRepository")
    private val parser = SearchConfigIconsParser()

    init {
        try {
@@ -76,7 +73,7 @@ class SearchEngineSelectorRepository(
            )
            val searchConfig = searchEngineSelectorConfig.selector.filterEngineConfiguration(config)

            val iconsList = searchConfigIconsUpdateService.fetchIconsRecords(searchEngineSelectorConfig.service)
            val iconsList = searchConfigIconsUpdateService.fetchIcons(searchEngineSelectorConfig.service)

            val searchEngineList = buildSearchEngineList(
                searchConfig = searchConfig,
@@ -98,7 +95,7 @@ class SearchEngineSelectorRepository(

    private fun buildSearchEngineList(
        searchConfig: RefinedSearchConfig,
        iconsList: List<RemoteSettingsRecord>,
        iconsList: List<SearchConfigIconsModel>,
    ): List<SearchEngine> {
        val searchEngineList = mutableListOf<SearchEngine>()
        searchConfig.engines.forEach { engine ->
@@ -107,8 +104,7 @@ class SearchEngineSelectorRepository(
                val searchEngine = try {
                    reader.loadStreamAPI(
                        engineDefinition = engine,
                        attachmentModel = searchConfigIconsUpdateService.fetchIconAttachment(it),
                        mimetype = it.attachment?.mimetype ?: "",
                        attachmentModel = it,
                    )
                } catch (exception: IllegalArgumentException) {
                    return@forEach
@@ -123,18 +119,17 @@ class SearchEngineSelectorRepository(

    private fun findMatchingIcon(
        engineIdentifier: String,
        iconsList: List<RemoteSettingsRecord>,
    ): RemoteSettingsRecord? {
        iconsList: List<SearchConfigIconsModel>,
    ): AttachmentModel? {
        iconsList.forEach { icon ->
            val parsedIcon = parser.parseRecord(icon)
            parsedIcon?.engineIdentifier?.forEach {
                val prefix = if (it.endsWith("*", true)) {
                    it.removeSuffix("*")
            icon.engineIdentifier.forEach { patternIdPrefix ->
                val prefix = if (patternIdPrefix.endsWith("*", true)) {
                    patternIdPrefix.removeSuffix("*")
                } else {
                    it
                    patternIdPrefix
                }
                if (engineIdentifier.startsWith(prefix)) {
                    return icon
                    return icon.attachment
                }
            }
        }
Loading