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.
5 #include "chrome/browser/android/popular_sites.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/json/json_reader.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/task_runner_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/net/file_downloader.h"
17 #include "chrome/browser/search_engines/template_url_service_factory.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "components/google/core/browser/google_util.h"
20 #include "components/search_engines/search_engine_type.h"
21 #include "components/search_engines/template_url_prepopulate_data.h"
22 #include "components/search_engines/template_url_service.h"
23 #include "content/public/browser/browser_thread.h"
25 using content::BrowserThread
;
29 const char kPopularSitesURLFormat
[] = "https://www.gstatic.com/chrome/ntp/%s";
30 const char kPopularSitesFilenameFormat
[] = "suggested_sites_%s_2.json";
31 const char kPopularSitesDefaultCountryCode
[] = "DEFAULT";
34 // Find out the country code of the user by using the Google country code if
35 // Google is the default search engine set. Fallback to a default if we can't
36 // make an educated guess.
37 std::string
GetCountryCode(Profile
* profile
) {
40 const TemplateURLService
* template_url_service
=
41 TemplateURLServiceFactory::GetForProfile(profile
);
42 DCHECK(template_url_service
);
44 const TemplateURL
* default_provider
=
45 template_url_service
->GetDefaultSearchProvider();
46 // It's possible to not have a default provider in the case that the default
47 // search engine is defined by policy.
48 if (!default_provider
)
49 return kPopularSitesDefaultCountryCode
;
51 bool is_google_search_engine
= TemplateURLPrepopulateData::GetEngineType(
52 *default_provider
, template_url_service
->search_terms_data()) ==
53 SearchEngineType::SEARCH_ENGINE_GOOGLE
;
55 if (!is_google_search_engine
)
56 return kPopularSitesDefaultCountryCode
;
58 GURL search_url
= default_provider
->GenerateSearchURL(
59 template_url_service
->search_terms_data());
61 std::string country_code
=
62 base::ToUpperASCII(google_util::GetGoogleCountryCode(search_url
));
67 std::string
GetPopularSitesFilename(Profile
* profile
,
68 const std::string
& filename
) {
69 if (!filename
.empty())
72 return base::StringPrintf(kPopularSitesFilenameFormat
,
73 GetCountryCode(profile
).c_str());
76 base::FilePath
GetPopularSitesPath(Profile
* profile
,
77 const std::string
& filename
) {
79 PathService::Get(chrome::DIR_USER_DATA
, &dir
);
80 return dir
.AppendASCII(GetPopularSitesFilename(profile
, filename
));
83 GURL
GetPopularSitesURL(Profile
* profile
, const std::string
& filename
) {
84 return GURL(base::StringPrintf(kPopularSitesURLFormat
,
85 GetPopularSitesFilename(profile
, filename
).c_str()));
88 scoped_ptr
<std::vector
<PopularSites::Site
>> ReadAndParseJsonFile(
89 const base::FilePath
& path
) {
91 if (!base::ReadFileToString(path
, &json
)) {
92 DLOG(WARNING
) << "Failed reading file";
96 scoped_ptr
<base::Value
> value
=
97 base::JSONReader::Read(json
, base::JSON_ALLOW_TRAILING_COMMAS
);
98 base::ListValue
* list
;
99 if (!value
|| !value
->GetAsList(&list
)) {
100 DLOG(WARNING
) << "Failed parsing json";
104 scoped_ptr
<std::vector
<PopularSites::Site
>> sites(
105 new std::vector
<PopularSites::Site
>);
106 for (size_t i
= 0; i
< list
->GetSize(); i
++) {
107 base::DictionaryValue
* item
;
108 if (!list
->GetDictionary(i
, &item
))
110 base::string16 title
;
112 if (!item
->GetString("title", &title
) || !item
->GetString("url", &url
))
114 std::string favicon_url
;
115 item
->GetString("favicon_url", &favicon_url
);
116 std::string thumbnail_url
;
117 item
->GetString("thumbnail_url", &thumbnail_url
);
119 sites
->push_back(PopularSites::Site(title
, GURL(url
), GURL(favicon_url
),
120 GURL(thumbnail_url
)));
128 PopularSites::Site::Site(const base::string16
& title
,
130 const GURL
& favicon_url
,
131 const GURL
& thumbnail_url
)
134 favicon_url(favicon_url
),
135 thumbnail_url(thumbnail_url
) {}
137 PopularSites::Site::~Site() {}
139 PopularSites::PopularSites(Profile
* profile
,
140 const std::string
& filename
,
141 net::URLRequestContextGetter
* request_context
,
142 const FinishedCallback
& callback
)
143 : callback_(callback
), weak_ptr_factory_(this) {
144 base::FilePath path
= GetPopularSitesPath(profile
, filename
);
145 downloader_
.reset(new FileDownloader(
146 GetPopularSitesURL(profile
, filename
), path
, request_context
,
147 base::Bind(&PopularSites::OnDownloadDone
, base::Unretained(this), path
)));
150 PopularSites::~PopularSites() {}
152 void PopularSites::OnDownloadDone(const base::FilePath
& path
, bool success
) {
154 base::PostTaskAndReplyWithResult(
155 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
156 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN
).get(),
158 base::Bind(&ReadAndParseJsonFile
, path
),
159 base::Bind(&PopularSites::OnJsonParsed
,
160 weak_ptr_factory_
.GetWeakPtr()));
162 DLOG(WARNING
) << "Download failed";
163 callback_
.Run(false);
169 void PopularSites::OnJsonParsed(scoped_ptr
<std::vector
<Site
>> sites
) {
174 callback_
.Run(!!sites
);