Commit 1843462f authored by Gayane Petrosyan's avatar Gayane Petrosyan Committed by Commit Bot

[NTP] Calc and store custom background color V2.

When user selects new custom background, use thumbnail from image
collections to fetche and calculate calculate the most frequent color on
the image. The calculated color is then stored in prefs with the rest of
the background info.

Bug: 874325
Change-Id: I5905b583f22174a491749543e922512e6b47caf0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1612235
Commit-Queue: Gayane Petrosyan <gayane@chromium.org>
Reviewed-by: default avatarNicolas Ouellet-Payeur <nicolaso@chromium.org>
Reviewed-by: default avatarGayane Petrosyan <gayane@chromium.org>
Reviewed-by: default avatarKyle Milka <kmilka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660899}
parent 8ed2bfc7
......@@ -267,6 +267,23 @@ void NtpBackgroundService::AddValidBackdropUrlForTesting(const GURL& url) {
collection_images_.push_back(image);
}
void NtpBackgroundService::AddValidBackdropUrlWithThumbnailForTesting(
const GURL& url,
const GURL& thumbnail_url) {
CollectionImage image;
image.image_url = url;
image.thumbnail_image_url = thumbnail_url;
collection_images_.push_back(image);
}
const GURL& NtpBackgroundService::GetThumbnailUrl(const GURL& image_url) {
for (auto& image : collection_images_) {
if (image.image_url == image_url)
return image.thumbnail_image_url;
}
return GURL::EmptyGURL();
}
void NtpBackgroundService::NotifyObservers(FetchComplete fetch_complete) {
for (auto& observer : observers_) {
switch (fetch_complete) {
......
......@@ -55,6 +55,13 @@ class NtpBackgroundService : public KeyedService {
void AddValidBackdropUrlForTesting(const GURL& url);
void AddValidBackdropUrlWithThumbnailForTesting(const GURL& url,
const GURL& thumbnail_url);
// Returns thumbnail url for the given image url if its valid. Otherwise,
// returns empty url.
const GURL& GetThumbnailUrl(const GURL& image_url);
// Returns the currently cached CollectionInfo, if any.
const std::vector<CollectionInfo>& collection_info() const {
return collection_info_;
......
......@@ -261,3 +261,14 @@ TEST_F(NtpBackgroundServiceTest, CheckValidAndInvalidBackdropUrls) {
EXPECT_FALSE(service()->IsValidBackdropUrl(
GURL("https://wallpapers.co/another_image")));
}
TEST_F(NtpBackgroundServiceTest, GetThumbnailUrl) {
const GURL kInvalidUrl("foo");
const GURL kValidUrl("https://www.foo.com");
const GURL kValidThumbnailUrl("https://www.foo.com/thumbnail");
service()->AddValidBackdropUrlWithThumbnailForTesting(kValidUrl,
kValidThumbnailUrl);
EXPECT_EQ(kValidThumbnailUrl, service()->GetThumbnailUrl(kValidUrl));
EXPECT_EQ(GURL::EmptyGURL(), service()->GetThumbnailUrl(kInvalidUrl));
}
......@@ -17,6 +17,7 @@
#include "base/task/post_task.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/image_fetcher/image_decoder_impl.h"
#include "chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/background/ntp_background_service.h"
......@@ -51,7 +52,9 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/url_data_source.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
#include "ui/native_theme/dark_mode_observer.h"
......@@ -63,6 +66,8 @@ const char kNtpCustomBackgroundAttributionLine2[] = "attribution_line_2";
const char kNtpCustomBackgroundAttributionActionURL[] =
"attribution_action_url";
const char kImageFetcherUmaClientName[] = "NtpCustomBackgrounds";
base::DictionaryValue GetBackgroundInfoAsDict(
const GURL& background_url,
const std::string& attribution_line_1,
......@@ -81,6 +86,33 @@ base::DictionaryValue GetBackgroundInfoAsDict(
return background_info;
}
// |GetBackgroundInfoWithColor| has to return new object so that updated version
// gets synced.
base::DictionaryValue GetBackgroundInfoWithColor(
const base::DictionaryValue* background_info,
const SkColor color) {
base::DictionaryValue new_background_info;
auto url = const_cast<base::Value&&>(
*background_info->FindKey(kNtpCustomBackgroundURL));
auto attribution_line_1 = const_cast<base::Value&&>(
*background_info->FindKey(kNtpCustomBackgroundAttributionLine1));
auto attribution_line_2 = const_cast<base::Value&&>(
*background_info->FindKey(kNtpCustomBackgroundAttributionLine2));
auto action_url = const_cast<base::Value&&>(
*background_info->FindKey(kNtpCustomBackgroundAttributionActionURL));
new_background_info.SetKey(kNtpCustomBackgroundURL, url.Clone());
new_background_info.SetKey(kNtpCustomBackgroundAttributionLine1,
attribution_line_1.Clone());
new_background_info.SetKey(kNtpCustomBackgroundAttributionLine1,
attribution_line_2.Clone());
new_background_info.SetKey(kNtpCustomBackgroundAttributionActionURL,
action_url.Clone());
new_background_info.SetKey(kNtpCustomBackgroundMainColor,
base::Value((int)color));
return new_background_info;
}
base::Value NtpCustomBackgroundDefaults() {
base::Value defaults(base::Value::Type::DICTIONARY);
defaults.SetKey(kNtpCustomBackgroundURL,
......@@ -115,6 +147,8 @@ void DoDeleteThumbnailDataIfExists(
} // namespace
const char kNtpCustomBackgroundMainColor[] = "background_main_color";
// Keeps track of any changes in search engine provider and notifies
// InstantService if a third-party search provider (i.e. a third-party NTP) is
// being used.
......@@ -231,6 +265,11 @@ InstantService::InstantService(Profile* profile)
prefs::kNtpCustomBackgroundDict,
base::BindRepeating(&InstantService::UpdateBackgroundFromSync,
weak_ptr_factory_.GetWeakPtr()));
image_fetcher_ = std::make_unique<image_fetcher::ImageFetcherImpl>(
std::make_unique<ImageDecoderImpl>(),
content::BrowserContext::GetDefaultStoragePartition(profile_)
->GetURLLoaderFactoryForBrowserProcess());
}
InstantService::~InstantService() = default;
......@@ -383,6 +422,12 @@ void InstantService::SetCustomBackgroundURLWithAttributions(
RemoveLocalBackgroundImageCopy();
if (background_url.is_valid() && is_backdrop_url) {
const GURL& thumbnail_url =
background_service_->GetThumbnailUrl(background_url);
FetchCustomBackground(background_url, thumbnail_url.is_valid()
? thumbnail_url
: background_url);
base::DictionaryValue background_info = GetBackgroundInfoAsDict(
background_url, attribution_line_1, attribution_line_2, action_url);
pref_service_->Set(prefs::kNtpCustomBackgroundDict, background_info);
......@@ -723,6 +768,62 @@ void InstantService::ResetToDefault() {
ResetCustomBackgroundThemeInfo();
}
void InstantService::UpdateCustomBackgroundColor(
const GURL& image_url,
const gfx::Image& fetched_image,
const image_fetcher::RequestMetadata& metadata) {
constexpr color_utils::HSL kNoBounds = {-1, -1, -1};
const SkColor color = color_utils::CalculateKMeanColorOfBitmap(
*fetched_image.ToSkBitmap(), fetched_image.Height(), kNoBounds, kNoBounds,
false);
// Update background color only if the selected background is still the same.
const base::DictionaryValue* background_info =
pref_service_->GetDictionary(prefs::kNtpCustomBackgroundDict);
if (!background_info)
return;
GURL current_bg_url(
background_info->FindKey(kNtpCustomBackgroundURL)->GetString());
if (current_bg_url == image_url) {
pref_service_->Set(prefs::kNtpCustomBackgroundDict,
GetBackgroundInfoWithColor(background_info, color));
}
}
void InstantService::FetchCustomBackground(const GURL& image_url,
const GURL& fetch_url) {
DCHECK(!fetch_url.is_empty());
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("ntp_custom_background",
R"(
semantics {
sender: "Desktop Chrome background fetcher"
description:
"Fetch New Tab Page custom background for color calculation."
trigger:
"User selects new background on the New Tab Page."
data: "The only data sent is the path to an image"
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"Users cannot disable this feature. The feature is enabled by "
"default."
policy_exception_justification: "Not implemented."
})");
image_fetcher::ImageFetcherParams params(traffic_annotation,
kImageFetcherUmaClientName);
image_fetcher_->FetchImage(
image_url,
base::BindOnce(&InstantService::UpdateCustomBackgroundColor,
weak_ptr_factory_.GetWeakPtr(), image_url),
std::move(params));
}
bool InstantService::IsCustomBackgroundPrefValid(GURL& custom_background_url) {
const base::DictionaryValue* background_info =
profile_->GetPrefs()->GetDictionary(prefs::kNtpCustomBackgroundDict);
......@@ -777,3 +878,8 @@ void InstantService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
false);
registry->RegisterBooleanPref(prefs::kNtpUseMostVisitedTiles, false);
}
void InstantService::SetImageFetcherForTesting(
image_fetcher::ImageFetcher* image_fetcher) {
image_fetcher_ = base::WrapUnique(image_fetcher);
}
......@@ -18,6 +18,7 @@
#include "base/optional.h"
#include "build/build_config.h"
#include "components/history/core/browser/history_types.h"
#include "components/image_fetcher/core/image_fetcher_impl.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/ntp_tiles/most_visited_sites.h"
#include "components/ntp_tiles/ntp_tile.h"
......@@ -47,6 +48,8 @@ namespace ui {
class DarkModeObserver;
} // namespace ui
extern const char kNtpCustomBackgroundMainColor[];
// Tracks render process host IDs that are associated with Instant, i.e.
// processes that are used to render an NTP. Also responsible for keeping
// necessary information (most visited tiles and theme info) updated in those
......@@ -154,11 +157,22 @@ class InstantService : public KeyedService,
// tests.
virtual void ResetToDefault();
// Calculates the most frequent color of the image and stores it in prefs.
void UpdateCustomBackgroundColor(
const GURL& image_url,
const gfx::Image& fetched_image,
const image_fetcher::RequestMetadata& metadata);
// Fetches the image for the given |fetch_url|.
void FetchCustomBackground(const GURL& image_url, const GURL& fetch_url);
private:
class SearchProviderObserver;
friend class InstantExtendedTest;
friend class InstantUnitTestBase;
friend class LocalNTPBackgroundsAndDarkModeTest;
friend class TestInstantService;
FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ProcessIsolation);
FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, DeleteThumbnailDataIfExists);
......@@ -229,6 +243,8 @@ class InstantService : public KeyedService,
void CreateDarkModeObserver(ui::NativeTheme* theme);
void SetImageFetcherForTesting(image_fetcher::ImageFetcher* image_fetcher);
Profile* const profile_;
// The process ids associated with Instant processes.
......@@ -261,6 +277,8 @@ class InstantService : public KeyedService,
NtpBackgroundService* background_service_;
std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
base::WeakPtrFactory<InstantService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(InstantService);
......
......@@ -55,6 +55,18 @@ class MockInstantService : public InstantService {
MOCK_METHOD0(ResetCustomBackgroundThemeInfo, void());
};
bool CheckBackgroundColor(SkColor color,
const base::DictionaryValue* background_info) {
if (!background_info)
return false;
const base::Value* background_color =
background_info->FindKey(kNtpCustomBackgroundMainColor);
if (!background_color)
return false;
return color == static_cast<uint32_t>(background_color->GetInt());
}
} // namespace
using InstantServiceTest = InstantUnitTestBase;
......@@ -576,3 +588,45 @@ TEST_F(InstantServiceTest, LocalImageDoesNotHaveAttribution) {
EXPECT_EQ(std::string(), theme_info->custom_background_attribution_line_2);
EXPECT_EQ(GURL(), theme_info->custom_background_attribution_action_url);
}
TEST_F(InstantServiceTest, TestUpdateCustomBackgroundColor) {
SkBitmap bitmap;
bitmap.allocN32Pixels(32, 32);
bitmap.eraseColor(SK_ColorRED);
gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap);
sync_preferences::TestingPrefServiceSyncable* pref_service =
profile()->GetTestingPrefService();
ASSERT_FALSE(instant_service_->IsCustomBackgroundSet());
// Background color will not update if no background is set.
instant_service_->UpdateCustomBackgroundColor(
GURL(), image, image_fetcher::RequestMetadata());
EXPECT_FALSE(CheckBackgroundColor(
SK_ColorRED,
pref_service->GetDictionary(prefs::kNtpCustomBackgroundDict)));
const GURL kUrl("https://www.foo.com");
const std::string kAttributionLine1 = "foo";
const std::string kAttributionLine2 = "bar";
const GURL kActionUrl("https://www.bar.com");
SetUserSelectedDefaultSearchProvider("{google:baseURL}");
instant_service_->AddValidBackdropUrlForTesting(kUrl);
instant_service_->SetCustomBackgroundURLWithAttributions(
kUrl, kAttributionLine1, kAttributionLine2, kActionUrl);
// Background color will not update if current background url changed.
instant_service_->UpdateCustomBackgroundColor(
GURL("different_url"), image, image_fetcher::RequestMetadata());
EXPECT_FALSE(CheckBackgroundColor(
SK_ColorRED,
pref_service->GetDictionary(prefs::kNtpCustomBackgroundDict)));
// Background color should update.
instant_service_->UpdateCustomBackgroundColor(
kUrl, image, image_fetcher::RequestMetadata());
EXPECT_TRUE(CheckBackgroundColor(
SK_ColorRED,
pref_service->GetDictionary(prefs::kNtpCustomBackgroundDict)));
}
......@@ -20,6 +20,7 @@
#include "chrome/test/base/search_test_utils.h"
#include "components/google/core/browser/google_pref_names.h"
#include "components/google/core/browser/google_url_tracker.h"
#include "components/image_fetcher/core/mock_image_fetcher.h"
#include "components/search/search.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_service.h"
......@@ -42,6 +43,9 @@ void InstantUnitTestBase::SetUp() {
UIThreadSearchTermsData::SetGoogleBaseURL("https://www.google.com/");
SetUserSelectedDefaultSearchProvider("{google:baseURL}");
instant_service_ = InstantServiceFactory::GetForProfile(profile());
instant_service_->SetImageFetcherForTesting(
new testing::NiceMock<image_fetcher::MockImageFetcher>());
}
void InstantUnitTestBase::TearDown() {
......
......@@ -21,15 +21,27 @@
#include "chrome/common/search/instant_types.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/image_fetcher/core/mock_image_fetcher.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_registry.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using LocalNTPCustomBackgroundsTest = InProcessBrowserTest;
class TestInstantService {
public:
explicit TestInstantService(Profile* profile) {
instant_service = InstantServiceFactory::GetForProfile(profile);
instant_service->SetImageFetcherForTesting(
new testing::NiceMock<image_fetcher::MockImageFetcher>());
}
InstantService* get_instant_service() { return instant_service; }
private:
InstantService* instant_service;
};
IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsTest,
EmbeddedSearchAPIEndToEnd) {
content::WebContents* active_tab =
......@@ -41,9 +53,9 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsTest,
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Check that a URL with no attributions can be set.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(browser()->profile());
instant_service->AddValidBackdropUrlForTesting(GURL("https://www.test.com/"));
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("https://www.test.com/"));
EXPECT_TRUE(content::ExecuteScript(active_tab,
"window.chrome.embeddedSearch.newTabPage."
"setBackgroundURL('https://www.test.com/"
......@@ -76,9 +88,9 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsTest, AttributionSetAndReset) {
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Set a custom background attribution via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(browser()->profile());
instant_service->AddValidBackdropUrlForTesting(GURL("https://www.test.com/"));
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("https://www.test.com/"));
EXPECT_TRUE(content::ExecuteScript(active_tab,
"window.chrome.embeddedSearch.newTabPage."
"setBackgroundURLWithAttributions('https:/"
......@@ -120,9 +132,8 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsTest,
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Set a custom background image via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(browser()->profile());
instant_service->AddValidBackdropUrlForTesting(
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("chrome-search://local-ntp/background1.jpg"));
EXPECT_TRUE(content::ExecuteScript(
active_tab,
......@@ -166,9 +177,8 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsTest,
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Set a custom background image via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(browser()->profile());
instant_service->AddValidBackdropUrlForTesting(
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("chrome-search://local-ntp/background1.jpg"));
ASSERT_TRUE(content::ExecuteScript(
active_tab,
......@@ -268,9 +278,9 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsThemeTest,
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Set a custom background attribution via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(profile());
instant_service->AddValidBackdropUrlForTesting(GURL("https://www.test.com/"));
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("https://www.test.com/"));
ASSERT_TRUE(content::ExecuteScript(active_tab,
"window.chrome.embeddedSearch.newTabPage."
"setBackgroundURLWithAttributions('https:/"
......@@ -327,9 +337,8 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsThemeTest,
local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
// Set a custom background image via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(profile());
instant_service->AddValidBackdropUrlForTesting(
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("chrome-search://local-ntp/background1.jpg"));
ASSERT_TRUE(content::ExecuteScript(
active_tab,
......@@ -392,9 +401,8 @@ IN_PROC_BROWSER_TEST_F(LocalNTPCustomBackgroundsThemeTest,
EXPECT_TRUE(result);
// Set a custom background image via the EmbeddedSearch API.
InstantService* instant_service =
InstantServiceFactory::GetForProfile(profile());
instant_service->AddValidBackdropUrlForTesting(
TestInstantService test_instant_service(browser()->profile());
test_instant_service.get_instant_service()->AddValidBackdropUrlForTesting(
GURL("chrome-search://local-ntp/background1.jpg"));
ASSERT_TRUE(content::ExecuteScript(
active_tab,
......@@ -440,6 +448,8 @@ class LocalNTPBackgroundsAndDarkModeTest
InstantServiceFactory::GetForProfile(browser()->profile());
theme()->SetDarkMode(true);
instant_service->SetDarkModeThemeForTesting(theme());
instant_service->SetImageFetcherForTesting(
new testing::NiceMock<image_fetcher::MockImageFetcher>());
}
InstantService* instant_service;
......@@ -534,5 +544,3 @@ IN_PROC_BROWSER_TEST_F(LocalNTPBackgroundsAndDarkModeTest,
EXPECT_TRUE(GetIsDarkModeApplied(active_tab));
EXPECT_TRUE(GetIsLightChipsApplied(active_tab));
}
} // namespace
......@@ -157,6 +157,7 @@ Refer to README.md for content description and update process.
<item id="network_location_request" hash_code="96590038" type="2" content_hash_code="80741011" os_list="linux,windows" semantics_fields="2,3,4,5" policy_fields="-1" file_path="services/device/geolocation/network_location_request.cc"/>
<item id="network_time_component" hash_code="46188932" type="0" content_hash_code="28051857" os_list="linux,windows" file_path="components/network_time/network_time_tracker.cc"/>
<item id="ntp_contextual_suggestions_fetch" hash_code="95711309" type="0" deprecated="2019-04-18" content_hash_code="107035434" file_path=""/>
<item id="ntp_custom_background" hash_code="92125886" type="0" content_hash_code="61176452" os_list="linux,windows" file_path="chrome/browser/search/instant_service.cc"/>
<item id="ntp_custom_link_checker_request" hash_code="78408551" type="0" deprecated="2018-10-26" content_hash_code="13407730" file_path=""/>
<item id="ntp_icon_source" hash_code="29197139" type="0" content_hash_code="16399294" os_list="linux,windows" file_path="chrome/browser/search/ntp_icon_source.cc"/>
<item id="ntp_snippets_fetch" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment