1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/search/instant_service.h"
6
7 #include <stddef.h>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/file_util.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/path_service.h"
15 #include "base/scoped_observer.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/task/post_task.h"
19 #include "base/task/thread_pool.h"
20 #include "base/time/clock.h"
21 #include "build/build_config.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/image_fetcher/image_decoder_impl.h"
24 #include "chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/search/background/ntp_background_service_factory.h"
27 #include "chrome/browser/search/chrome_colors/chrome_colors_service.h"
28 #include "chrome/browser/search/instant_service_factory.h"
29 #include "chrome/browser/search/instant_service_observer.h"
30 #include "chrome/browser/search/local_ntp_source.h"
31 #include "chrome/browser/search/most_visited_iframe_source.h"
32 #include "chrome/browser/search/ntp_icon_source.h"
33 #include "chrome/browser/search/search.h"
34 #include "chrome/browser/search_engines/template_url_service_factory.h"
35 #include "chrome/browser/themes/theme_properties.h"
36 #include "chrome/browser/themes/theme_service.h"
37 #include "chrome/browser/themes/theme_service_factory.h"
38 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
39 #include "chrome/browser/ui/webui/favicon_source.h"
40 #include "chrome/browser/ui/webui/theme_source.h"
41 #include "chrome/common/chrome_paths.h"
42 #include "chrome/common/pref_names.h"
43 #include "chrome/common/search/search.mojom.h"
44 #include "chrome/common/url_constants.h"
45 #include "chrome/grit/theme_resources.h"
46 #include "components/favicon_base/favicon_url_parser.h"
47 #include "components/ntp_tiles/constants.h"
48 #include "components/prefs/pref_registry_simple.h"
49 #include "components/prefs/pref_service.h"
50 #include "components/search/ntp_features.h"
51 #include "components/search/search_provider_observer.h"
52 #include "components/sync_preferences/pref_service_syncable.h"
53 #include "content/public/browser/browser_context.h"
54 #include "content/public/browser/browser_task_traits.h"
55 #include "content/public/browser/browser_thread.h"
56 #include "content/public/browser/notification_service.h"
57 #include "content/public/browser/notification_types.h"
58 #include "content/public/browser/render_process_host.h"
59 #include "content/public/browser/storage_partition.h"
60 #include "content/public/browser/url_data_source.h"
61 #include "extensions/browser/extension_registry.h"
62 #include "extensions/common/extension.h"
63 #include "mojo/public/cpp/bindings/associated_remote.h"
64 #include "ui/gfx/color_analysis.h"
65 #include "ui/gfx/color_palette.h"
66 #include "ui/gfx/color_utils.h"
67
68 namespace {
69
70 const char kNtpCustomBackgroundURL[] = "background_url";
71 const char kNtpCustomBackgroundAttributionLine1[] = "attribution_line_1";
72 const char kNtpCustomBackgroundAttributionLine2[] = "attribution_line_2";
73 const char kNtpCustomBackgroundAttributionActionURL[] =
74 "attribution_action_url";
75 const char kNtpCustomBackgroundCollectionId[] = "collection_id";
76 const char kNtpCustomBackgroundResumeToken[] = "resume_token";
77 const char kNtpCustomBackgroundRefreshTimestamp[] = "refresh_timestamp";
78
79 const char kCustomBackgroundsUmaClientName[] = "NtpCustomBackgrounds";
80
GetBackgroundInfoAsDict(const GURL & background_url,const std::string & attribution_line_1,const std::string & attribution_line_2,const GURL & action_url,const base::Optional<std::string> & collection_id,const base::Optional<std::string> & resume_token,const base::Optional<int> refresh_timestamp)81 base::DictionaryValue GetBackgroundInfoAsDict(
82 const GURL& background_url,
83 const std::string& attribution_line_1,
84 const std::string& attribution_line_2,
85 const GURL& action_url,
86 const base::Optional<std::string>& collection_id,
87 const base::Optional<std::string>& resume_token,
88 const base::Optional<int> refresh_timestamp) {
89 base::DictionaryValue background_info;
90 background_info.SetKey(kNtpCustomBackgroundURL,
91 base::Value(background_url.spec()));
92 background_info.SetKey(kNtpCustomBackgroundAttributionLine1,
93 base::Value(attribution_line_1));
94 background_info.SetKey(kNtpCustomBackgroundAttributionLine2,
95 base::Value(attribution_line_2));
96 background_info.SetKey(kNtpCustomBackgroundAttributionActionURL,
97 base::Value(action_url.spec()));
98 background_info.SetKey(kNtpCustomBackgroundCollectionId,
99 base::Value(collection_id.value_or("")));
100 background_info.SetKey(kNtpCustomBackgroundResumeToken,
101 base::Value(resume_token.value_or("")));
102 background_info.SetKey(kNtpCustomBackgroundRefreshTimestamp,
103 base::Value(refresh_timestamp.value_or(0)));
104
105 return background_info;
106 }
107
108 // |GetBackgroundInfoWithColor| has to return new object so that updated version
109 // gets synced.
GetBackgroundInfoWithColor(const base::DictionaryValue * background_info,const SkColor color)110 base::DictionaryValue GetBackgroundInfoWithColor(
111 const base::DictionaryValue* background_info,
112 const SkColor color) {
113 base::DictionaryValue new_background_info;
114 auto url = const_cast<base::Value&&>(
115 *background_info->FindKey(kNtpCustomBackgroundURL));
116 auto attribution_line_1 = const_cast<base::Value&&>(
117 *background_info->FindKey(kNtpCustomBackgroundAttributionLine1));
118 auto attribution_line_2 = const_cast<base::Value&&>(
119 *background_info->FindKey(kNtpCustomBackgroundAttributionLine2));
120 auto action_url = const_cast<base::Value&&>(
121 *background_info->FindKey(kNtpCustomBackgroundAttributionActionURL));
122 auto collection_id = const_cast<base::Value&&>(
123 *background_info->FindKey(kNtpCustomBackgroundCollectionId));
124 auto resume_token = const_cast<base::Value&&>(
125 *background_info->FindKey(kNtpCustomBackgroundResumeToken));
126 auto refresh_timestamp = const_cast<base::Value&&>(
127 *background_info->FindKey(kNtpCustomBackgroundRefreshTimestamp));
128
129 new_background_info.SetKey(kNtpCustomBackgroundURL, url.Clone());
130 new_background_info.SetKey(kNtpCustomBackgroundAttributionLine1,
131 attribution_line_1.Clone());
132 new_background_info.SetKey(kNtpCustomBackgroundAttributionLine2,
133 attribution_line_2.Clone());
134 new_background_info.SetKey(kNtpCustomBackgroundAttributionActionURL,
135 action_url.Clone());
136 new_background_info.SetKey(kNtpCustomBackgroundMainColor,
137 base::Value((int)color));
138 new_background_info.SetKey(kNtpCustomBackgroundCollectionId,
139 collection_id.Clone());
140 new_background_info.SetKey(kNtpCustomBackgroundResumeToken,
141 resume_token.Clone());
142 new_background_info.SetKey(kNtpCustomBackgroundRefreshTimestamp,
143 refresh_timestamp.Clone());
144 return new_background_info;
145 }
146
NtpCustomBackgroundDefaults()147 base::Value NtpCustomBackgroundDefaults() {
148 base::Value defaults(base::Value::Type::DICTIONARY);
149 defaults.SetKey(kNtpCustomBackgroundURL,
150 base::Value(base::Value::Type::STRING));
151 defaults.SetKey(kNtpCustomBackgroundAttributionLine1,
152 base::Value(base::Value::Type::STRING));
153 defaults.SetKey(kNtpCustomBackgroundAttributionLine2,
154 base::Value(base::Value::Type::STRING));
155 defaults.SetKey(kNtpCustomBackgroundAttributionActionURL,
156 base::Value(base::Value::Type::STRING));
157 defaults.SetKey(kNtpCustomBackgroundCollectionId,
158 base::Value(base::Value::Type::STRING));
159 defaults.SetKey(kNtpCustomBackgroundResumeToken,
160 base::Value(base::Value::Type::STRING));
161 defaults.SetKey(kNtpCustomBackgroundRefreshTimestamp,
162 base::Value(base::Value::Type::INTEGER));
163 return defaults;
164 }
165
CopyFileToProfilePath(const base::FilePath & from_path,const base::FilePath & profile_path)166 void CopyFileToProfilePath(const base::FilePath& from_path,
167 const base::FilePath& profile_path) {
168 base::CopyFile(from_path,
169 profile_path.AppendASCII(
170 chrome::kChromeSearchLocalNtpBackgroundFilename));
171 }
172
173 // |GetBitmapMainColor| just wraps |CalculateKMeanColorOfBitmap|.
174 // As |CalculateKMeanColorOfBitmap| is overloaded, it cannot be bind for async
175 // call.
GetBitmapMainColor(const SkBitmap & bitmap)176 SkColor GetBitmapMainColor(const SkBitmap& bitmap) {
177 return color_utils::CalculateKMeanColorOfBitmap(bitmap);
178 }
179
180 } // namespace
181
182 const char kNtpCustomBackgroundMainColor[] = "background_main_color";
183
InstantService(Profile * profile)184 InstantService::InstantService(Profile* profile)
185 : profile_(profile),
186 most_visited_info_(std::make_unique<InstantMostVisitedInfo>()),
187 pref_service_(profile_->GetPrefs()),
188 native_theme_(ui::NativeTheme::GetInstanceForNativeUi()),
189 background_updated_timestamp_(base::TimeTicks::Now()),
190 clock_(base::DefaultClock::GetInstance()) {
191 // The initialization below depends on a typical set of browser threads. Skip
192 // it if we are running in a unit test without the full suite.
193 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI))
194 return;
195
196 registrar_.Add(this,
197 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
198 content::NotificationService::AllSources());
199 registrar_.Add(this,
200 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
201 content::NotificationService::AllSources());
202
203 most_visited_sites_ = ChromeMostVisitedSitesFactory::NewForProfile(profile_);
204 if (most_visited_sites_) {
205 // Determine if we are using a third-party NTP. Custom links should only be
206 // enabled for the default NTP.
207 TemplateURLService* template_url_service =
208 TemplateURLServiceFactory::GetForProfile(profile_);
209 if (template_url_service) {
210 search_provider_observer_ = std::make_unique<SearchProviderObserver>(
211 template_url_service,
212 base::BindRepeating(&InstantService::OnSearchProviderChanged,
213 weak_ptr_factory_.GetWeakPtr()));
214 }
215
216 // If custom links are enabled, an additional tile may be returned making up
217 // to ntp_tiles::kMaxNumCustomLinks custom links including the
218 // "Add shortcut" button.
219 most_visited_sites_->SetMostVisitedURLsObserver(
220 this, ntp_tiles::kMaxNumMostVisited);
221 most_visited_sites_->EnableCustomLinks(IsCustomLinksEnabled());
222 }
223
224 most_visited_info_->use_most_visited = !IsCustomLinksEnabled();
225 most_visited_info_->is_visible =
226 pref_service_->GetBoolean(prefs::kNtpShortcutsVisible);
227
228 background_service_ = NtpBackgroundServiceFactory::GetForProfile(profile_);
229
230 // Listen for theme installation.
231 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
232 content::Source<ThemeService>(
233 ThemeServiceFactory::GetForProfile(profile_)));
234
235 // Set up the data sources that Instant uses on the NTP.
236 content::URLDataSource::Add(profile_,
237 std::make_unique<ThemeSource>(profile_));
238 content::URLDataSource::Add(profile_,
239 std::make_unique<LocalNtpSource>(profile_));
240 content::URLDataSource::Add(profile_,
241 std::make_unique<NtpIconSource>(profile_));
242 content::URLDataSource::Add(
243 profile_, std::make_unique<FaviconSource>(
244 profile_, chrome::FaviconUrlFormat::kFaviconLegacy));
245 content::URLDataSource::Add(profile_,
246 std::make_unique<MostVisitedIframeSource>());
247
248 // Update theme info when the pref is changed via Sync.
249 pref_change_registrar_.Init(pref_service_);
250 pref_change_registrar_.Add(
251 prefs::kNtpCustomBackgroundDict,
252 base::BindRepeating(&InstantService::UpdateBackgroundFromSync,
253 weak_ptr_factory_.GetWeakPtr()));
254
255 image_fetcher_ = std::make_unique<image_fetcher::ImageFetcherImpl>(
256 std::make_unique<ImageDecoderImpl>(),
257 content::BrowserContext::GetDefaultStoragePartition(profile_)
258 ->GetURLLoaderFactoryForBrowserProcess());
259
260 theme_observer_.Add(native_theme_);
261
262 if (background_service_)
263 background_service_observer_.Add(background_service_);
264 }
265
266 InstantService::~InstantService() = default;
267
AddInstantProcess(int process_id)268 void InstantService::AddInstantProcess(int process_id) {
269 process_ids_.insert(process_id);
270 }
271
IsInstantProcess(int process_id) const272 bool InstantService::IsInstantProcess(int process_id) const {
273 return process_ids_.find(process_id) != process_ids_.end();
274 }
275
AddObserver(InstantServiceObserver * observer)276 void InstantService::AddObserver(InstantServiceObserver* observer) {
277 observers_.AddObserver(observer);
278 }
279
RemoveObserver(InstantServiceObserver * observer)280 void InstantService::RemoveObserver(InstantServiceObserver* observer) {
281 observers_.RemoveObserver(observer);
282 }
283
OnNewTabPageOpened()284 void InstantService::OnNewTabPageOpened() {
285 if (most_visited_sites_) {
286 most_visited_sites_->Refresh();
287 }
288 }
289
DeleteMostVisitedItem(const GURL & url)290 void InstantService::DeleteMostVisitedItem(const GURL& url) {
291 if (most_visited_sites_) {
292 most_visited_sites_->AddOrRemoveBlockedUrl(url, true);
293 }
294 }
295
UndoMostVisitedDeletion(const GURL & url)296 void InstantService::UndoMostVisitedDeletion(const GURL& url) {
297 if (most_visited_sites_) {
298 most_visited_sites_->AddOrRemoveBlockedUrl(url, false);
299 }
300 }
301
UndoAllMostVisitedDeletions()302 void InstantService::UndoAllMostVisitedDeletions() {
303 if (most_visited_sites_) {
304 most_visited_sites_->ClearBlockedUrls();
305 }
306 }
307
AddCustomLink(const GURL & url,const std::string & title)308 bool InstantService::AddCustomLink(const GURL& url, const std::string& title) {
309 return most_visited_sites_ &&
310 most_visited_sites_->AddCustomLink(url, base::UTF8ToUTF16(title));
311 }
312
UpdateCustomLink(const GURL & url,const GURL & new_url,const std::string & new_title)313 bool InstantService::UpdateCustomLink(const GURL& url,
314 const GURL& new_url,
315 const std::string& new_title) {
316 return most_visited_sites_ && most_visited_sites_->UpdateCustomLink(
317 url, new_url, base::UTF8ToUTF16(new_title));
318 }
319
ReorderCustomLink(const GURL & url,int new_pos)320 bool InstantService::ReorderCustomLink(const GURL& url, int new_pos) {
321 return most_visited_sites_ &&
322 most_visited_sites_->ReorderCustomLink(url, new_pos);
323 }
324
DeleteCustomLink(const GURL & url)325 bool InstantService::DeleteCustomLink(const GURL& url) {
326 return most_visited_sites_ && most_visited_sites_->DeleteCustomLink(url);
327 }
328
UndoCustomLinkAction()329 bool InstantService::UndoCustomLinkAction() {
330 // Non-Google NTPs are not supported.
331 if (!most_visited_sites_ || !search_provider_observer_ ||
332 !search_provider_observer_->is_google()) {
333 return false;
334 }
335 most_visited_sites_->UndoCustomLinkAction();
336 return true;
337 }
338
ResetCustomLinks()339 bool InstantService::ResetCustomLinks() {
340 // Non-Google NTPs are not supported.
341 if (!most_visited_sites_ || !search_provider_observer_ ||
342 !search_provider_observer_->is_google()) {
343 return false;
344 }
345 most_visited_sites_->UninitializeCustomLinks();
346 return true;
347 }
348
ToggleMostVisitedOrCustomLinks()349 bool InstantService::ToggleMostVisitedOrCustomLinks() {
350 // Non-Google NTPs are not supported.
351 if (!most_visited_sites_ || !search_provider_observer_ ||
352 !search_provider_observer_->is_google()) {
353 return false;
354 }
355 bool use_most_visited =
356 !pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles);
357 pref_service_->SetBoolean(prefs::kNtpUseMostVisitedTiles, use_most_visited);
358 most_visited_info_->use_most_visited = use_most_visited;
359 bool was_initialized = most_visited_sites_->IsCustomLinksInitialized();
360
361 // Custom links is enabled if Most Visited is disabled.
362 // Note: This will eventually call |NotifyAboutMostVisitedInfo|, except in the
363 // case below.
364 most_visited_sites_->EnableCustomLinks(!use_most_visited);
365
366 // If custom links is enabled but not initialized, MostVisitedSites will not
367 // notify |OnURLsAvailable| and |NotifyAboutMostVisitedInfo| will not be
368 // called.
369 //
370 // This is because custom links are considered Most Visited items before
371 // initialization. As such their NTPTile metadata is the same, and observers
372 // are not notified if the list of NTPTiles was not changed.
373 //
374 // Therefore, we need to manually call |NotifyAboutMostVisitedInfo| if the
375 // user has never customized their shortcuts.
376 //
377 // For more details, see custom_links_mananger.h and most_visited_sites.h.
378 if (!was_initialized && !most_visited_sites_->IsCustomLinksInitialized()) {
379 NotifyAboutMostVisitedInfo();
380 }
381
382 return true;
383 }
384
ToggleShortcutsVisibility(bool do_notify)385 bool InstantService::ToggleShortcutsVisibility(bool do_notify) {
386 // Non-Google NTPs are not supported.
387 if (!most_visited_sites_ || !search_provider_observer_ ||
388 !search_provider_observer_->is_google()) {
389 return false;
390 }
391 bool is_visible = !pref_service_->GetBoolean(prefs::kNtpShortcutsVisible);
392 pref_service_->SetBoolean(prefs::kNtpShortcutsVisible, is_visible);
393 most_visited_info_->is_visible = is_visible;
394
395 if (do_notify) {
396 NotifyAboutMostVisitedInfo();
397 }
398 return true;
399 }
400
UpdateNtpTheme()401 void InstantService::UpdateNtpTheme() {
402 ApplyOrResetCustomBackgroundNtpTheme();
403 SetNtpElementsNtpTheme();
404
405 GetInitializedNtpTheme()->custom_background_disabled_by_policy =
406 IsCustomBackgroundDisabledByPolicy();
407
408 NotifyAboutNtpTheme();
409 }
410
UpdateBackgroundFromSync()411 void InstantService::UpdateBackgroundFromSync() {
412 // Any incoming change to synced background data should clear the local image.
413 pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false);
414 RemoveLocalBackgroundImageCopy();
415 UpdateNtpTheme();
416 }
417
UpdateMostVisitedInfo()418 void InstantService::UpdateMostVisitedInfo() {
419 NotifyAboutMostVisitedInfo();
420 }
421
ResetCustomBackgroundInfo()422 void InstantService::ResetCustomBackgroundInfo() {
423 SetCustomBackgroundInfo(GURL(), std::string(), std::string(), GURL(),
424 std::string());
425 }
426
SetCustomBackgroundInfo(const GURL & background_url,const std::string & attribution_line_1,const std::string & attribution_line_2,const GURL & action_url,const std::string & collection_id)427 void InstantService::SetCustomBackgroundInfo(
428 const GURL& background_url,
429 const std::string& attribution_line_1,
430 const std::string& attribution_line_2,
431 const GURL& action_url,
432 const std::string& collection_id) {
433 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
434 if (IsCustomBackgroundDisabledByPolicy()) {
435 return;
436 }
437 bool is_backdrop_collection =
438 background_service_ &&
439 background_service_->IsValidBackdropCollection(collection_id);
440 bool is_backdrop_url =
441 background_service_ &&
442 background_service_->IsValidBackdropUrl(background_url);
443
444 bool need_forced_refresh =
445 pref_service_->GetBoolean(prefs::kNtpCustomBackgroundLocalToDevice) &&
446 pref_service_->FindPreference(prefs::kNtpCustomBackgroundDict)
447 ->IsDefaultValue();
448 pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false);
449 RemoveLocalBackgroundImageCopy();
450
451 background_updated_timestamp_ = base::TimeTicks::Now();
452
453 if (!collection_id.empty() && is_backdrop_collection) {
454 background_service_->FetchNextCollectionImage(collection_id, base::nullopt);
455 } else if (background_url.is_valid() && is_backdrop_url) {
456 const GURL& thumbnail_url =
457 background_service_->GetThumbnailUrl(background_url);
458 FetchCustomBackground(
459 background_updated_timestamp_,
460 thumbnail_url.is_valid() ? thumbnail_url : background_url);
461
462 base::DictionaryValue background_info = GetBackgroundInfoAsDict(
463 background_url, attribution_line_1, attribution_line_2, action_url,
464 base::nullopt, base::nullopt, base::nullopt);
465 pref_service_->Set(prefs::kNtpCustomBackgroundDict, background_info);
466 } else {
467 pref_service_->ClearPref(prefs::kNtpCustomBackgroundDict);
468
469 // If this device was using a local image and did not have a non-local
470 // background saved, UpdateBackgroundFromSync will not fire. Therefore, we
471 // need to force a refresh here.
472 if (need_forced_refresh) {
473 UpdateNtpTheme();
474 }
475 }
476 }
477
SetBackgroundToLocalResource()478 void InstantService::SetBackgroundToLocalResource() {
479 background_updated_timestamp_ = base::TimeTicks::Now();
480 pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, true);
481 UpdateNtpTheme();
482 }
483
SelectLocalBackgroundImage(const base::FilePath & path)484 void InstantService::SelectLocalBackgroundImage(const base::FilePath& path) {
485 if (IsCustomBackgroundDisabledByPolicy()) {
486 return;
487 }
488 base::ThreadPool::PostTaskAndReply(
489 FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
490 base::BindOnce(&CopyFileToProfilePath, path, profile_->GetPath()),
491 base::BindOnce(&InstantService::SetBackgroundToLocalResource,
492 weak_ptr_factory_.GetWeakPtr()));
493 }
494
GetInitializedNtpTheme()495 NtpTheme* InstantService::GetInitializedNtpTheme() {
496 RefreshBackgroundIfNeeded();
497
498 if (!theme_)
499 BuildNtpTheme();
500 return theme_.get();
501 }
502
SetNativeThemeForTesting(ui::NativeTheme * theme)503 void InstantService::SetNativeThemeForTesting(ui::NativeTheme* theme) {
504 theme_observer_.RemoveAll();
505 native_theme_ = theme;
506 theme_observer_.Add(native_theme_);
507 }
508
Shutdown()509 void InstantService::Shutdown() {
510 process_ids_.clear();
511
512 if (most_visited_sites_) {
513 most_visited_sites_.reset();
514 }
515 }
516
OnNextCollectionImageAvailable()517 void InstantService::OnNextCollectionImageAvailable() {
518 auto image = background_service_->next_image();
519 std::string attribution1;
520 std::string attribution2;
521 if (image.attribution.size() > 0)
522 attribution1 = image.attribution[0];
523 if (image.attribution.size() > 1)
524 attribution2 = image.attribution[1];
525
526 std::string resume_token = background_service_->next_image_resume_token();
527 int64_t timestamp = (clock_->Now() + base::TimeDelta::FromDays(1)).ToTimeT();
528
529 base::DictionaryValue background_info = GetBackgroundInfoAsDict(
530 image.image_url, attribution1, attribution2, image.attribution_action_url,
531 image.collection_id, resume_token, timestamp);
532
533 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
534 pref_service_->Set(prefs::kNtpCustomBackgroundDict, background_info);
535 }
536
OnNtpBackgroundServiceShuttingDown()537 void InstantService::OnNtpBackgroundServiceShuttingDown() {
538 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
539 background_service_observer_.RemoveAll();
540 background_service_ = nullptr;
541 }
542
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)543 void InstantService::Observe(int type,
544 const content::NotificationSource& source,
545 const content::NotificationDetails& details) {
546 switch (type) {
547 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
548 break;
549 }
550 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
551 content::RenderProcessHost* rph =
552 content::Source<content::RenderProcessHost>(source).ptr();
553 Profile* renderer_profile =
554 static_cast<Profile*>(rph->GetBrowserContext());
555 if (profile_ == renderer_profile)
556 OnRendererProcessTerminated(rph->GetID());
557 break;
558 }
559 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
560 theme_ = nullptr;
561 UpdateNtpTheme();
562 break;
563 default:
564 NOTREACHED() << "Unexpected notification type in InstantService.";
565 }
566 }
567
OnRendererProcessTerminated(int process_id)568 void InstantService::OnRendererProcessTerminated(int process_id) {
569 process_ids_.erase(process_id);
570 }
571
OnNativeThemeUpdated(ui::NativeTheme * observed_theme)572 void InstantService::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
573 DCHECK_EQ(observed_theme, native_theme_);
574 // Force the theme information to rebuild so the correct using_dark_colors
575 // value is sent to the renderer.
576 BuildNtpTheme();
577 UpdateNtpTheme();
578 }
579
OnSearchProviderChanged()580 void InstantService::OnSearchProviderChanged() {
581 DCHECK(most_visited_sites_);
582 most_visited_sites_->EnableCustomLinks(IsCustomLinksEnabled());
583 }
584
OnURLsAvailable(const std::map<ntp_tiles::SectionType,ntp_tiles::NTPTilesVector> & sections)585 void InstantService::OnURLsAvailable(
586 const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
587 sections) {
588 DCHECK(most_visited_sites_);
589 most_visited_info_->items.clear();
590 // Use only personalized tiles for instant service.
591 const ntp_tiles::NTPTilesVector& tiles =
592 sections.at(ntp_tiles::SectionType::PERSONALIZED);
593 for (const ntp_tiles::NTPTile& tile : tiles) {
594 InstantMostVisitedItem item;
595 item.url = tile.url;
596 item.title = tile.title;
597 item.favicon = tile.favicon_url;
598 item.source = tile.source;
599 item.title_source = tile.title_source;
600 item.data_generation_time = tile.data_generation_time;
601 most_visited_info_->items.push_back(item);
602 }
603 most_visited_info_->items_are_custom_links =
604 (most_visited_sites_ && most_visited_sites_->IsCustomLinksInitialized());
605
606 NotifyAboutMostVisitedInfo();
607 }
608
OnIconMadeAvailable(const GURL & site_url)609 void InstantService::OnIconMadeAvailable(const GURL& site_url) {}
610
NotifyAboutMostVisitedInfo()611 void InstantService::NotifyAboutMostVisitedInfo() {
612 for (InstantServiceObserver& observer : observers_)
613 observer.MostVisitedInfoChanged(*most_visited_info_);
614 }
615
NotifyAboutNtpTheme()616 void InstantService::NotifyAboutNtpTheme() {
617 for (InstantServiceObserver& observer : observers_)
618 observer.NtpThemeChanged(*theme_);
619 }
620
IsCustomLinksEnabled()621 bool InstantService::IsCustomLinksEnabled() {
622 return search_provider_observer_ && search_provider_observer_->is_google() &&
623 !pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles);
624 }
625
BuildNtpTheme()626 void InstantService::BuildNtpTheme() {
627 // Get theme information from theme service.
628 theme_ = std::make_unique<NtpTheme>();
629
630 // Get if the current theme is the default theme.
631 ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
632 theme_->using_default_theme = theme_service->UsingDefaultTheme();
633
634 theme_->using_dark_colors = native_theme_->ShouldUseDarkColors();
635
636 // Get theme colors.
637 const ui::ThemeProvider& theme_provider =
638 ThemeService::GetThemeProviderForProfile(profile_);
639
640 // Set colors.
641 theme_->background_color =
642 theme_provider.GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
643 theme_->text_color_light =
644 theme_provider.GetColor(ThemeProperties::COLOR_NTP_TEXT_LIGHT);
645 SetNtpElementsNtpTheme();
646
647 if (base::FeatureList::IsEnabled(ntp_features::kRealboxMatchOmniboxTheme)) {
648 theme_->search_box.bg =
649 GetOmniboxColor(&theme_provider, OmniboxPart::LOCATION_BAR_BACKGROUND);
650 theme_->search_box.icon =
651 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_ICON);
652 theme_->search_box.icon_selected = GetOmniboxColor(
653 &theme_provider, OmniboxPart::RESULTS_ICON, OmniboxPartState::SELECTED);
654 theme_->search_box.placeholder =
655 GetOmniboxColor(&theme_provider, OmniboxPart::LOCATION_BAR_TEXT_DIMMED);
656 theme_->search_box.results_bg =
657 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_BACKGROUND);
658 theme_->search_box.results_bg_hovered =
659 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_BACKGROUND,
660 OmniboxPartState::HOVERED);
661 theme_->search_box.results_bg_selected =
662 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_BACKGROUND,
663 OmniboxPartState::SELECTED);
664 theme_->search_box.results_dim =
665 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_DIMMED);
666 theme_->search_box.results_dim_selected =
667 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_DIMMED,
668 OmniboxPartState::SELECTED);
669 theme_->search_box.results_text =
670 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_DEFAULT);
671 theme_->search_box.results_text_selected =
672 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_DEFAULT,
673 OmniboxPartState::SELECTED);
674 theme_->search_box.results_url =
675 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_URL);
676 theme_->search_box.results_url_selected =
677 GetOmniboxColor(&theme_provider, OmniboxPart::RESULTS_TEXT_URL,
678 OmniboxPartState::SELECTED);
679 theme_->search_box.text = GetOmniboxColor(
680 &theme_provider, OmniboxPart::LOCATION_BAR_TEXT_DEFAULT);
681 }
682
683 if (theme_service->UsingExtensionTheme()) {
684 const extensions::Extension* extension =
685 extensions::ExtensionRegistry::Get(profile_)
686 ->enabled_extensions()
687 .GetByID(theme_service->GetThemeID());
688 if (extension) {
689 theme_->theme_id = theme_service->GetThemeID();
690 theme_->theme_name = extension->name();
691
692 if (theme_provider.HasCustomImage(IDR_THEME_NTP_BACKGROUND)) {
693 theme_->has_theme_image = true;
694
695 // Set theme background image horizontal alignment.
696 int alignment = theme_provider.GetDisplayProperty(
697 ThemeProperties::NTP_BACKGROUND_ALIGNMENT);
698 if (alignment & ThemeProperties::ALIGN_LEFT)
699 theme_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_LEFT;
700 else if (alignment & ThemeProperties::ALIGN_RIGHT)
701 theme_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_RIGHT;
702 else
703 theme_->image_horizontal_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
704
705 // Set theme background image vertical alignment.
706 if (alignment & ThemeProperties::ALIGN_TOP)
707 theme_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_TOP;
708 else if (alignment & ThemeProperties::ALIGN_BOTTOM)
709 theme_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_BOTTOM;
710 else
711 theme_->image_vertical_alignment = THEME_BKGRND_IMAGE_ALIGN_CENTER;
712
713 // Set theme background image tiling.
714 int tiling = theme_provider.GetDisplayProperty(
715 ThemeProperties::NTP_BACKGROUND_TILING);
716 switch (tiling) {
717 case ThemeProperties::NO_REPEAT:
718 theme_->image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
719 break;
720 case ThemeProperties::REPEAT_X:
721 theme_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_X;
722 break;
723 case ThemeProperties::REPEAT_Y:
724 theme_->image_tiling = THEME_BKGRND_IMAGE_REPEAT_Y;
725 break;
726 case ThemeProperties::REPEAT:
727 theme_->image_tiling = THEME_BKGRND_IMAGE_REPEAT;
728 break;
729 }
730
731 theme_->has_attribution =
732 theme_provider.HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
733 }
734 }
735 } else if (theme_service->UsingAutogeneratedTheme()) {
736 theme_->color_picked = theme_service->GetAutogeneratedThemeColor();
737 theme_->color_id =
738 chrome_colors::ChromeColorsService::GetColorId(theme_->color_picked);
739 theme_->color_dark =
740 theme_provider.GetColor(ThemeProperties::COLOR_FRAME_ACTIVE);
741 theme_->color_light =
742 theme_provider.GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
743 }
744 }
745
ApplyOrResetCustomBackgroundNtpTheme()746 void InstantService::ApplyOrResetCustomBackgroundNtpTheme() {
747 // Custom backgrounds for non-Google search providers are not supported.
748 if (!search::DefaultSearchProviderIsGoogle(profile_)) {
749 ResetCustomBackgroundNtpTheme();
750 return;
751 }
752
753 if (pref_service_->GetBoolean(prefs::kNtpCustomBackgroundLocalToDevice)) {
754 // Add a timestamp to the url to prevent the browser from using a cached
755 // version when "Upload an image" is used multiple times.
756 std::string time_string = std::to_string(base::Time::Now().ToTimeT());
757 std::string local_string(chrome::kChromeSearchLocalNtpBackgroundUrl);
758 GURL timestamped_url(local_string + "?ts=" + time_string);
759 GetInitializedNtpTheme()->custom_background_url = timestamped_url;
760 GetInitializedNtpTheme()->custom_background_attribution_line_1 =
761 std::string();
762 GetInitializedNtpTheme()->custom_background_attribution_line_2 =
763 std::string();
764 GetInitializedNtpTheme()->custom_background_attribution_action_url = GURL();
765 return;
766 }
767
768 // Attempt to get custom background URL from preferences.
769 GURL custom_background_url;
770 if (!IsCustomBackgroundPrefValid(custom_background_url)) {
771 ResetCustomBackgroundNtpTheme();
772 return;
773 }
774
775 ApplyCustomBackgroundNtpTheme();
776 }
777
ApplyCustomBackgroundNtpTheme()778 void InstantService::ApplyCustomBackgroundNtpTheme() {
779 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
780 const base::DictionaryValue* background_info =
781 pref_service_->GetDictionary(prefs::kNtpCustomBackgroundDict);
782 GURL custom_background_url(
783 background_info->FindKey(kNtpCustomBackgroundURL)->GetString());
784
785 std::string collection_id;
786 const base::Value* id_value =
787 background_info->FindKey(kNtpCustomBackgroundCollectionId);
788 if (id_value)
789 collection_id = id_value->GetString();
790
791 // Set custom background information in theme info (attributions are
792 // optional).
793 const base::Value* attribution_line_1 =
794 background_info->FindKey(kNtpCustomBackgroundAttributionLine1);
795 const base::Value* attribution_line_2 =
796 background_info->FindKey(kNtpCustomBackgroundAttributionLine2);
797 const base::Value* attribution_action_url =
798 background_info->FindKey(kNtpCustomBackgroundAttributionActionURL);
799 NtpTheme* theme = GetInitializedNtpTheme();
800 theme->custom_background_url = custom_background_url;
801 theme->collection_id = collection_id;
802
803 if (attribution_line_1) {
804 theme->custom_background_attribution_line_1 =
805 background_info->FindKey(kNtpCustomBackgroundAttributionLine1)
806 ->GetString();
807 }
808 if (attribution_line_2) {
809 theme->custom_background_attribution_line_2 =
810 background_info->FindKey(kNtpCustomBackgroundAttributionLine2)
811 ->GetString();
812 }
813 if (attribution_action_url) {
814 GURL action_url(
815 background_info->FindKey(kNtpCustomBackgroundAttributionActionURL)
816 ->GetString());
817
818 if (!action_url.SchemeIsCryptographic()) {
819 theme->custom_background_attribution_action_url = GURL();
820 } else {
821 theme->custom_background_attribution_action_url = action_url;
822 }
823 }
824 }
825
ResetCustomBackgroundNtpTheme()826 void InstantService::ResetCustomBackgroundNtpTheme() {
827 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
828 pref_service_->ClearPref(prefs::kNtpCustomBackgroundDict);
829 pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false);
830 RemoveLocalBackgroundImageCopy();
831 FallbackToDefaultNtpTheme();
832 }
833
FallbackToDefaultNtpTheme()834 void InstantService::FallbackToDefaultNtpTheme() {
835 NtpTheme* theme = GetInitializedNtpTheme();
836 theme->custom_background_url = GURL();
837 theme->custom_background_attribution_line_1 = std::string();
838 theme->custom_background_attribution_line_2 = std::string();
839 theme->custom_background_attribution_action_url = GURL();
840 theme->collection_id = std::string();
841 }
842
IsCustomBackgroundDisabledByPolicy()843 bool InstantService::IsCustomBackgroundDisabledByPolicy() {
844 // |prefs::kNtpCustomBackgroundDict| is managed by policy only if
845 // |policy::key::kNTPCustomBackgroundEnabled| is set to false and therefore
846 // should be empty.
847 bool managed =
848 pref_service_->IsManagedPreference(prefs::kNtpCustomBackgroundDict);
849 if (managed) {
850 DCHECK(
851 pref_service_->GetDictionary(prefs::kNtpCustomBackgroundDict)->empty());
852 }
853 return managed;
854 }
855
IsCustomBackgroundSet()856 bool InstantService::IsCustomBackgroundSet() {
857 if (pref_service_->GetBoolean(prefs::kNtpCustomBackgroundLocalToDevice))
858 return true;
859
860 GURL custom_background_url;
861 if (!IsCustomBackgroundPrefValid(custom_background_url))
862 return false;
863
864 return true;
865 }
866
AreShortcutsCustomized()867 bool InstantService::AreShortcutsCustomized() {
868 return most_visited_info_->items_are_custom_links;
869 }
870
GetCurrentShortcutSettings()871 std::pair<bool, bool> InstantService::GetCurrentShortcutSettings() {
872 bool using_most_visited =
873 pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles);
874 bool is_visible = pref_service_->GetBoolean(prefs::kNtpShortcutsVisible);
875 return std::make_pair(using_most_visited, is_visible);
876 }
877
ResetToDefault()878 void InstantService::ResetToDefault() {
879 ResetCustomLinks();
880 ResetCustomBackgroundNtpTheme();
881 pref_service_->SetBoolean(prefs::kNtpUseMostVisitedTiles, false);
882 pref_service_->SetBoolean(prefs::kNtpShortcutsVisible, true);
883 }
884
UpdateCustomBackgroundColorAsync(base::TimeTicks timestamp,const gfx::Image & fetched_image,const image_fetcher::RequestMetadata & metadata)885 void InstantService::UpdateCustomBackgroundColorAsync(
886 base::TimeTicks timestamp,
887 const gfx::Image& fetched_image,
888 const image_fetcher::RequestMetadata& metadata) {
889 // Calculate the bitmap color asynchronously as it is slow (1-2 seconds for
890 // the thumbnail). However, prefs should be updated on the main thread.
891 if (!fetched_image.IsEmpty()) {
892 base::ThreadPool::PostTaskAndReplyWithResult(
893 FROM_HERE, {base::TaskPriority::BEST_EFFORT},
894 base::BindOnce(&GetBitmapMainColor, *fetched_image.ToSkBitmap()),
895 base::BindOnce(&InstantService::UpdateCustomBackgroundPrefsWithColor,
896 weak_ptr_factory_.GetWeakPtr(), timestamp));
897 }
898 }
899
FetchCustomBackground(base::TimeTicks timestamp,const GURL & fetch_url)900 void InstantService::FetchCustomBackground(base::TimeTicks timestamp,
901 const GURL& fetch_url) {
902 DCHECK(!fetch_url.is_empty());
903
904 net::NetworkTrafficAnnotationTag traffic_annotation =
905 net::DefineNetworkTrafficAnnotation("ntp_custom_background",
906 R"(
907 semantics {
908 sender: "Desktop Chrome background fetcher"
909 description:
910 "Fetch New Tab Page custom background for color calculation."
911 trigger:
912 "User selects new background on the New Tab Page."
913 data: "The only data sent is the path to an image"
914 destination: GOOGLE_OWNED_SERVICE
915 }
916 policy {
917 cookies_allowed: NO
918 setting:
919 "Users cannot disable this feature. The feature is enabled by "
920 "default."
921 policy_exception_justification: "Not implemented."
922 })");
923
924 image_fetcher::ImageFetcherParams params(traffic_annotation,
925 kCustomBackgroundsUmaClientName);
926 image_fetcher_->FetchImage(
927 fetch_url,
928 base::BindOnce(&InstantService::UpdateCustomBackgroundColorAsync,
929 weak_ptr_factory_.GetWeakPtr(), timestamp),
930 std::move(params));
931 }
932
IsCustomBackgroundPrefValid(GURL & custom_background_url)933 bool InstantService::IsCustomBackgroundPrefValid(GURL& custom_background_url) {
934 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
935 const base::DictionaryValue* background_info =
936 profile_->GetPrefs()->GetDictionary(prefs::kNtpCustomBackgroundDict);
937 if (!background_info)
938 return false;
939
940 const base::Value* background_url =
941 background_info->FindKey(kNtpCustomBackgroundURL);
942 if (!background_url)
943 return false;
944
945 custom_background_url = GURL(background_url->GetString());
946 return custom_background_url.is_valid();
947 }
948
RemoveLocalBackgroundImageCopy()949 void InstantService::RemoveLocalBackgroundImageCopy() {
950 base::FilePath path = profile_->GetPath().AppendASCII(
951 chrome::kChromeSearchLocalNtpBackgroundFilename);
952 base::ThreadPool::PostTask(
953 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
954 base::BindOnce(base::GetDeleteFileCallback(), path));
955 }
956
AddValidBackdropUrlForTesting(const GURL & url) const957 void InstantService::AddValidBackdropUrlForTesting(const GURL& url) const {
958 background_service_->AddValidBackdropUrlForTesting(url);
959 }
960
AddValidBackdropCollectionForTesting(const std::string & collection_id) const961 void InstantService::AddValidBackdropCollectionForTesting(
962 const std::string& collection_id) const {
963 background_service_->AddValidBackdropCollectionForTesting(collection_id);
964 }
965
SetNextCollectionImageForTesting(const CollectionImage & image) const966 void InstantService::SetNextCollectionImageForTesting(
967 const CollectionImage& image) const {
968 background_service_->SetNextCollectionImageForTesting(image);
969 }
970
971 // static
RegisterProfilePrefs(PrefRegistrySimple * registry)972 void InstantService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
973 registry->RegisterDictionaryPref(
974 prefs::kNtpCustomBackgroundDict, NtpCustomBackgroundDefaults(),
975 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
976 registry->RegisterBooleanPref(prefs::kNtpCustomBackgroundLocalToDevice,
977 false);
978 registry->RegisterBooleanPref(prefs::kNtpUseMostVisitedTiles, false);
979 registry->RegisterBooleanPref(prefs::kNtpShortcutsVisible, true);
980 }
981
982 // static
ShouldServiceRequest(const GURL & url,content::BrowserContext * browser_context,int render_process_id)983 bool InstantService::ShouldServiceRequest(
984 const GURL& url,
985 content::BrowserContext* browser_context,
986 int render_process_id) {
987 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
988
989 auto* instant_service = InstantServiceFactory::GetForProfile(
990 static_cast<Profile*>(browser_context));
991
992 if (!instant_service)
993 return false;
994
995 // The process_id for the navigation request will be -1. If
996 // so, allow this request since it's not going to another renderer.
997 return render_process_id == -1 ||
998 instant_service->IsInstantProcess(render_process_id);
999 }
1000
UpdateCustomBackgroundPrefsWithColor(base::TimeTicks timestamp,SkColor color)1001 void InstantService::UpdateCustomBackgroundPrefsWithColor(
1002 base::TimeTicks timestamp,
1003 SkColor color) {
1004 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1005 // Update background color only if the selected background is still the same.
1006 const base::DictionaryValue* background_info =
1007 pref_service_->GetDictionary(prefs::kNtpCustomBackgroundDict);
1008 if (!background_info)
1009 return;
1010
1011 if (timestamp == background_updated_timestamp_) {
1012 pref_service_->Set(prefs::kNtpCustomBackgroundDict,
1013 GetBackgroundInfoWithColor(background_info, color));
1014 }
1015 }
1016
RefreshBackgroundIfNeeded()1017 void InstantService::RefreshBackgroundIfNeeded() {
1018 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1019 const base::DictionaryValue* background_info =
1020 profile_->GetPrefs()->GetDictionary(prefs::kNtpCustomBackgroundDict);
1021 int64_t refresh_timestamp = 0;
1022 const base::Value* timestamp_value =
1023 background_info->FindKey(kNtpCustomBackgroundRefreshTimestamp);
1024 if (timestamp_value)
1025 refresh_timestamp = timestamp_value->GetInt();
1026 if (refresh_timestamp == 0)
1027 return;
1028
1029 if (clock_->Now().ToTimeT() > refresh_timestamp) {
1030 std::string collection_id =
1031 background_info->FindKey(kNtpCustomBackgroundCollectionId)->GetString();
1032 std::string resume_token =
1033 background_info->FindKey(kNtpCustomBackgroundResumeToken)->GetString();
1034 background_service_->FetchNextCollectionImage(collection_id, resume_token);
1035 }
1036 }
1037
SetImageFetcherForTesting(image_fetcher::ImageFetcher * image_fetcher)1038 void InstantService::SetImageFetcherForTesting(
1039 image_fetcher::ImageFetcher* image_fetcher) {
1040 image_fetcher_ = base::WrapUnique(image_fetcher);
1041 }
1042
SetClockForTesting(base::Clock * clock)1043 void InstantService::SetClockForTesting(base::Clock* clock) {
1044 clock_ = clock;
1045 }
1046
SetNtpElementsNtpTheme()1047 void InstantService::SetNtpElementsNtpTheme() {
1048 NtpTheme* theme = GetInitializedNtpTheme();
1049 if (IsCustomBackgroundSet()) {
1050 theme->text_color = gfx::kGoogleGrey050;
1051 theme->logo_alternate = true;
1052 theme->logo_color = ThemeProperties::GetDefaultColor(
1053 ThemeProperties::COLOR_NTP_LOGO, false);
1054 theme->shortcut_color = ThemeProperties::GetDefaultColor(
1055 ThemeProperties::COLOR_NTP_SHORTCUT, false);
1056 } else {
1057 const ui::ThemeProvider& theme_provider =
1058 ThemeService::GetThemeProviderForProfile(profile_);
1059 theme->text_color =
1060 theme_provider.GetColor(ThemeProperties::COLOR_NTP_TEXT);
1061 theme->logo_alternate = theme_provider.GetDisplayProperty(
1062 ThemeProperties::NTP_LOGO_ALTERNATE) == 1;
1063 theme->logo_color =
1064 theme_provider.GetColor(ThemeProperties::COLOR_NTP_LOGO);
1065 theme->shortcut_color =
1066 theme_provider.GetColor(ThemeProperties::COLOR_NTP_SHORTCUT);
1067 }
1068 }
1069