blob: 505555af34e51de55af952ccf9701730c8c1fef2 [file] [log] [blame]
// Copyright 2024 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.tab_resumption;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.chrome.browser.page_image_service.ImageServiceBridge;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.ui.favicon.FaviconUtils;
import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool;
import org.chromium.components.browser_ui.widget.RoundedIconGenerator;
import org.chromium.components.favicon.LargeIconBridge;
import org.chromium.components.image_fetcher.ImageFetcher;
import org.chromium.components.image_fetcher.ImageFetcherConfig;
import org.chromium.components.image_fetcher.ImageFetcherFactory;
import org.chromium.page_image_service.mojom.ClientId;
import org.chromium.url.GURL;
/** Helper to retrieve or create an image to represent a URL. */
public class UrlImageProvider {
/** Callback to pass URL image Bitmap fetch results. */
public interface UrlImageCallback {
void onBitmap(Bitmap bitmap);
}
/** Factory methods for inner objects, abstracted to enable testing. */
public interface UrlImageSource {
LargeIconBridge createLargeIconBridge();
RoundedIconGenerator createIconGenerator();
}
protected final int mMinIconSizePx;
protected final int mDesiredIconSizePx;
protected final LargeIconBridge mLargeIconBridge;
protected final RoundedIconGenerator mIconGenerator;
private final boolean mUseSalientImage;
@Nullable private ImageServiceBridge mImageServiceBridge;
@Nullable private ImageFetcher mImageFetcher;
private int mSalientImageSizeBigPx;
private int mSalientImageSizeSmallPx;
UrlImageProvider(Profile profile, UrlImageSource source, Context context) {
Resources res = context.getResources();
mMinIconSizePx = res.getDimensionPixelSize(R.dimen.default_favicon_min_size);
mDesiredIconSizePx =
res.getDimensionPixelSize(R.dimen.tab_resumption_module_icon_source_size);
mLargeIconBridge = source.createLargeIconBridge();
mIconGenerator = source.createIconGenerator();
mUseSalientImage = TabResumptionModuleUtils.TAB_RESUMPTION_USE_SALIENT_IMAGE.getValue();
if (mUseSalientImage) {
mImageFetcher =
ImageFetcherFactory.createImageFetcher(
ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE,
profile.getProfileKey(),
GlobalDiscardableReferencePool.getReferencePool());
mImageServiceBridge =
new ImageServiceBridge(
ClientId.NTP_TAB_RESUMPTION,
ImageFetcher.TAB_RESUMPTION_MODULE_NAME,
profile,
mImageFetcher);
mSalientImageSizeBigPx =
res.getDimensionPixelSize(R.dimen.tab_resumption_module_single_icon_size);
mSalientImageSizeSmallPx = mDesiredIconSizePx;
}
}
UrlImageProvider(Profile profile, Context context) {
this(
profile,
new UrlImageSource() {
@Override
public LargeIconBridge createLargeIconBridge() {
return new LargeIconBridge(profile);
}
@Override
public RoundedIconGenerator createIconGenerator() {
return FaviconUtils.createRoundedRectangleIconGenerator(context);
}
},
context);
}
/**
* Clean up the C++ side of this class. After the call, this class instance shouldn't be used.
*/
public void destroy() {
mLargeIconBridge.destroy();
if (mImageServiceBridge != null) {
mImageServiceBridge.destroy();
}
if (mImageFetcher != null) {
mImageFetcher.destroy();
}
}
/**
* Asynchronously fetches a large favicon for a URL, and passes it to `callback`. If
* unavailable, then passes a solid filled circular icon with a single letter as fallback.
*
* @param pageUrl URL for favicon.
* @param callback Destination to pass resulting Bitmap.
*/
public void fetchImageForUrl(GURL pageUrl, UrlImageCallback callback) {
mLargeIconBridge.getLargeIconForUrl(
pageUrl,
mMinIconSizePx,
mDesiredIconSizePx,
(Bitmap icon, int fallbackColor, boolean isFallbackColorDefault, int iconType) -> {
if (icon == null) {
mIconGenerator.setBackgroundColor(fallbackColor);
icon = mIconGenerator.generateIconForUrl(pageUrl);
}
callback.onBitmap(icon);
});
}
/**
* Asynchronously fetches a salient image for a URL, and fallback to fetch the favicon if there
* isn't any salient image available.
*/
public void fetchSalientImageWithFallback(
@NonNull GURL pageUrl,
boolean showBigImage,
Callback<Bitmap> onSalientImageReadyCallback,
UrlImageCallback fallback) {
assert mUseSalientImage;
int imageSize = showBigImage ? mSalientImageSizeBigPx : mSalientImageSizeSmallPx;
mImageServiceBridge.fetchImageFor(
/* isAccountData= */ true,
pageUrl,
imageSize,
(bitmap) -> {
if (bitmap != null) {
onSalientImageReadyCallback.onResult((Bitmap) bitmap);
} else {
// Fallback to fetch the favicon.
fetchImageForUrl(pageUrl, fallback);
}
});
}
}