chromium/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckIconHelper.java

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.password_check.helper;

import android.content.Context;
import android.graphics.Bitmap;

import androidx.annotation.Nullable;
import androidx.core.util.Pair;

import org.chromium.base.Callback;
import org.chromium.chrome.browser.password_check.CompromisedCredential;
import org.chromium.chrome.browser.password_check.R;
import org.chromium.components.favicon.IconType;
import org.chromium.components.favicon.LargeIconBridge;
import org.chromium.url.GURL;

/** Helper used to fetch or create an appropriate icon for a compromised credential. */
public class PasswordCheckIconHelper {
    /** Data object containing all data required to set an icon or construct a fallback. */
    public static class FaviconOrFallback {
        public final String mUrlOrAppName;
        public final @Nullable Bitmap mIcon;
        public final int mFallbackColor;
        public final boolean mIsFallbackColorDefault;
        public final int mIconType;
        public final int mIconSize;

        FaviconOrFallback(
                String urlOrAppName,
                @Nullable Bitmap icon,
                int fallbackColor,
                boolean isFallbackColorDefault,
                int iconType,
                int iconSize) {
            mUrlOrAppName = urlOrAppName;
            mIcon = icon;
            mFallbackColor = fallbackColor;
            mIsFallbackColorDefault = isFallbackColorDefault;
            mIconType = iconType;
            mIconSize = iconSize;
        }
    }

    private final LargeIconBridge mLargeIconBridge;
    private final int mDesiredIconSize;

    public PasswordCheckIconHelper(LargeIconBridge largeIconBridge, int desiredIconSize) {
        mLargeIconBridge = largeIconBridge;
        mDesiredIconSize = desiredIconSize;
    }

    public void getLargeIcon(
            CompromisedCredential credential, Callback<FaviconOrFallback> iconCallback) {
        final Pair<GURL, String> originAndFallback = getIconOriginAndFallback(credential);
        if (!originAndFallback.first.isValid()) {
            iconCallback.onResult(
                    new FaviconOrFallback(
                            originAndFallback.second,
                            null,
                            0,
                            true,
                            IconType.INVALID,
                            mDesiredIconSize));
            return; // Abort because an invalid icon URLs will crash Chrome!
        }
        mLargeIconBridge.getLargeIconForUrl(
                originAndFallback.first,
                mDesiredIconSize,
                (icon, fallbackColor, hasDefaultColor, type) -> {
                    iconCallback.onResult(
                            new FaviconOrFallback(
                                    originAndFallback.second,
                                    icon,
                                    fallbackColor,
                                    hasDefaultColor,
                                    type,
                                    mDesiredIconSize));
                });
    }

    /**
     * @param faviconOrFallbackData A {@link FaviconOrFallback} containing color or fallback hints.
     * @param context A {@link Context} object used to load default colors if necessary.
     * @return A color (non-resource value) to use for monogram icons.
     */
    public static int getIconColor(
            PasswordCheckIconHelper.FaviconOrFallback faviconOrFallbackData, Context context) {
        return faviconOrFallbackData.mIsFallbackColorDefault
                ? context.getColor(R.color.default_favicon_background_color)
                : faviconOrFallbackData.mFallbackColor;
    }

    /**
     * Determines which origin to use for retrieving a favicon.
     * @param credential A {@link CompromisedCredential}.
     * @return A pair with (potentially invalid) icon origin and a fallback URL for monograms.
     */
    private static Pair<GURL, String> getIconOriginAndFallback(CompromisedCredential credential) {
        if (!credential.getAssociatedApp().isEmpty()) {
            return getIconOriginAndFallbackForApp(credential);
        }

        // Ideally, the sign-on realm is valid and has an adjacent, valid icon.
        GURL iconOrigin = new GURL(credential.getSignonRealm());
        String fallbackUrl = credential.getSignonRealm();
        if (!iconOrigin.isValid()) {
            // If the sign-on realm isn't valid, try the change URL instead.
            iconOrigin = new GURL(credential.getPasswordChangeUrl());
            fallbackUrl = credential.getPasswordChangeUrl();
        }
        if (!iconOrigin.isValid()) {
            // If neither URL is valid, try the display origin as a last, very weak hope.
            iconOrigin = credential.getAssociatedUrl();
            fallbackUrl = credential.getDisplayOrigin();
        }
        return new Pair<>(iconOrigin, fallbackUrl);
    }

    private static Pair<GURL, String> getIconOriginAndFallbackForApp(
            CompromisedCredential credential) {
        return new Pair<>(new GURL(credential.getDisplayOrigin()), credential.getDisplayOrigin());
    }
}