// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/supervised_user/android/favicon_fetcher.h"
#include <cstddef>
#include <memory>
#include "base/android/callback_android.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/task/cancelable_task_tracker.h"
#include "components/favicon/core/large_icon_service.h"
#include "components/favicon_base/favicon_callback.h"
#include "components/favicon_base/favicon_types.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "url/gurl.h"
FaviconFetcher::FaviconFetcher(
raw_ptr<favicon::LargeIconService> large_icon_service)
: large_icon_service_(large_icon_service) {}
FaviconFetcher::~FaviconFetcher() {}
void FaviconFetcher::Destroy() {
delete this;
}
void FaviconFetcher::OnFaviconDownloaded(
const GURL& url,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
FaviconDimensions faviconDimensions,
favicon_base::GoogleFaviconServerRequestStatus status) {
if (status == favicon_base::GoogleFaviconServerRequestStatus::SUCCESS) {
FetchFavicon(url, false, faviconDimensions.min_source_size_in_pixel,
faviconDimensions.desired_size_in_pixel, std::move(callback));
} else {
LOG(WARNING)
<< "Unable to obtain a favicon image with the required specs for "
<< url.host();
Destroy();
}
}
void FaviconFetcher::ExecuteFaviconCallback(
const base::android::ScopedJavaGlobalRef<jobject>& callback,
SkBitmap bitmap) {
base::android::RunObjectCallbackAndroid(callback,
gfx::ConvertToJavaBitmap(bitmap));
}
void FaviconFetcher::OnGetFaviconFromCacheFinished(
const GURL& url,
bool continue_to_server,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
FaviconDimensions faviconDimensions,
const favicon_base::LargeIconImageResult& image_result) {
if (!image_result.image.IsEmpty()) {
SkBitmap faviconBitmap =
image_result.image.AsImageSkia().GetRepresentation(1.0f).GetBitmap();
// Return the image to the caller by executing the callback and destroy this
// instance.
ExecuteFaviconCallback(callback, faviconBitmap);
Destroy();
return;
}
// Try to fetch the favicon from a Google favicon server.
if (continue_to_server) {
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("favicon_fetcher_get_favicon", R"(
semantics {
sender: "Favicon"
description:
"Sends a request to a Google server to retrieve a favicon bitmap "
"for a URL that a supervised user has requested approval to "
"access from their parents."
trigger:
"A request can be sent if Chrome does not have a favicon for a "
"particular page that supervised users are requesting approval to "
"access from their parents."
data: "Page URL and desired icon size."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting: "This feature cannot be disabled by settings."
policy_exception_justification: "Not implemented."
}
comments: "No policy is necessary as the request cannot be turned off via settings."
"A request for a favicon will always be sent for supervised users."
)");
large_icon_service_
->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
url,
/*should_trim_page_url_path=*/false, traffic_annotation,
base::BindOnce(&FaviconFetcher::OnFaviconDownloaded,
base::Unretained(this), url, std::move(callback),
faviconDimensions));
} else {
Destroy();
}
}
base::WeakPtr<FaviconFetcher> FaviconFetcher::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void FaviconFetcher::FetchFavicon(
const GURL& url,
bool continue_to_server,
int min_source_side_size_in_pixel,
int desired_side_size_in_pixel,
const base::android::ScopedJavaGlobalRef<jobject>& callback) {
FaviconDimensions faviconDimensions;
faviconDimensions.min_source_size_in_pixel = min_source_side_size_in_pixel;
faviconDimensions.desired_size_in_pixel = desired_side_size_in_pixel;
large_icon_service_->GetLargeIconImageOrFallbackStyleForPageUrl(
url, faviconDimensions.min_source_size_in_pixel,
faviconDimensions.desired_size_in_pixel,
base::BindOnce(&FaviconFetcher::OnGetFaviconFromCacheFinished,
base::Unretained(this), url, continue_to_server,
std::move(callback), faviconDimensions),
&task_tracker_);
}