chromium/components/privacy_sandbox/android/java/src/org/chromium/components/privacy_sandbox/WebsiteExceptionRowPreference.java

// Copyright 2023 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.components.privacy_sandbox;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;

import androidx.preference.PreferenceViewHolder;

import org.chromium.components.browser_ui.settings.ChromeImageViewPreference;
import org.chromium.components.browser_ui.settings.FaviconViewUtils;
import org.chromium.components.browser_ui.site_settings.Website;
import org.chromium.components.content_settings.ContentSettingValues;
import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.url.GURL;

/** Represents a row element for the 3PCD exceptions site list. */
public class WebsiteExceptionRowPreference extends ChromeImageViewPreference {
    /** Interface for the callback when the exception is deleted. */
    public interface WebsiteExceptionDeletedCallback {
        void refreshBlockingExceptions();
    }

    // Whether the favicon has been fetched already.
    private boolean mFaviconFetchInProgress;

    private Website mSite;

    private TrackingProtectionDelegate mDelegate;

    private Context mContext;

    private WebsiteExceptionDeletedCallback mCallback;

    private static final String ANY_SUBDOMAIN_PATTERN = "[*.]";

    WebsiteExceptionRowPreference(
            Context context,
            Website site,
            TrackingProtectionDelegate delegate,
            WebsiteExceptionDeletedCallback callback) {
        super(context);
        mSite = site;
        mFaviconFetchInProgress = false;
        mDelegate = delegate;
        mContext = context;
        mCallback = callback;

        setTitle(site.getTitle());
        var exception = mSite.getContentSettingException(ContentSettingsType.COOKIES);
        if (exception != null && exception.hasExpiration()) {
            var expirationInDays = exception.getExpirationInDays();
            setSummary(
                    (expirationInDays == 0)
                            ? getContext()
                                    .getString(R.string.tracking_protection_expires_today_label)
                            : getContext()
                                    .getResources()
                                    .getQuantityString(
                                            R.plurals.tracking_protection_expires_label,
                                            expirationInDays,
                                            expirationInDays));
        } else {
            setSummary(getContext().getString(R.string.tracking_protection_never_expires_label));
        }
        setImageView(
                R.drawable.ic_delete_white_24dp,
                getContext()
                        .getString(R.string.tracking_protection_delete_site_label, site.getTitle()),
                (View view) -> {
                    deleteException();
                });
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);

        // Manually apply ListItemStartIcon style to draw the outer circle in the right size.
        ImageView icon = (ImageView) holder.findViewById(android.R.id.icon);
        FaviconViewUtils.formatIconForFavicon(getContext().getResources(), icon);

        if (!mFaviconFetchInProgress && faviconUrl().isValid()) {
            // Start the favicon fetching. Will respond in onFaviconAvailable.
            mDelegate
                    .getSiteSettingsDelegate(mContext)
                    .getFaviconImageForURL(faviconUrl(), this::onFaviconAvailable);
            mFaviconFetchInProgress = true;
        }
    }

    private void onFaviconAvailable(Drawable drawable) {
        if (drawable != null) {
            setIcon(drawable);
        }
    }

    /** Returns the url of the site to fetch a favicon for. */
    private GURL faviconUrl() {
        String origin = mSite.getMainAddress().getOrigin();
        GURL uri =
                new GURL(
                        origin.contains(ANY_SUBDOMAIN_PATTERN)
                                ? origin.replace(ANY_SUBDOMAIN_PATTERN, "")
                                : origin);
        return UrlUtilities.clearPort(uri);
    }

    private void deleteException() {
        mSite.setContentSetting(
                mDelegate.getBrowserContext(),
                ContentSettingsType.COOKIES,
                ContentSettingValues.DEFAULT);
        mCallback.refreshBlockingExceptions();
    }
}