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