[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 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/android/most_visited_sites.h" |
| 6 | |
| 7 | #include "base/android/jni_android.h" |
| 8 | #include "base/android/jni_array.h" |
| 9 | #include "base/android/jni_string.h" |
| 10 | #include "base/android/scoped_java_ref.h" |
[email protected] | d33adb40d | 2014-06-03 21:38:46 | [diff] [blame] | 11 | #include "base/callback.h" |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 12 | #include "base/command_line.h" |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 13 | #include "base/metrics/histogram.h" |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 14 | #include "base/metrics/sparse_histogram.h" |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 15 | #include "base/prefs/pref_service.h" |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 16 | #include "base/strings/string_number_conversions.h" |
treib | eba6cee | 2015-09-09 13:25:59 | [diff] [blame] | 17 | #include "base/strings/string_util.h" |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 18 | #include "base/strings/stringprintf.h" |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 19 | #include "base/strings/utf_string_conversions.h" |
[email protected] | 6d21c70 | 2014-05-15 06:10:21 | [diff] [blame] | 20 | #include "base/time/time.h" |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 21 | #include "chrome/browser/android/popular_sites.h" |
jitendra.ks | 30f0339 | 2015-01-28 09:47:18 | [diff] [blame] | 22 | #include "chrome/browser/history/top_sites_factory.h" |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 23 | #include "chrome/browser/profiles/profile.h" |
| 24 | #include "chrome/browser/profiles/profile_android.h" |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 25 | #include "chrome/browser/search/suggestions/suggestions_service_factory.h" |
[email protected] | 81e09e7 | 2014-05-07 13:41:22 | [diff] [blame] | 26 | #include "chrome/browser/search/suggestions/suggestions_source.h" |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 27 | #include "chrome/browser/sync/profile_sync_service.h" |
| 28 | #include "chrome/browser/sync/profile_sync_service_factory.h" |
[email protected] | 81e09e7 | 2014-05-07 13:41:22 | [diff] [blame] | 29 | #include "chrome/browser/thumbnails/thumbnail_list_source.h" |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 30 | #include "chrome/common/chrome_switches.h" |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 31 | #include "chrome/common/pref_names.h" |
sdefresne | 0da3bc0 | 2015-01-29 18:26:35 | [diff] [blame] | 32 | #include "components/history/core/browser/top_sites.h" |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 33 | #include "components/pref_registry/pref_registry_syncable.h" |
[email protected] | bdceb3ba | 2014-07-25 16:47:48 | [diff] [blame] | 34 | #include "components/suggestions/suggestions_service.h" |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 35 | #include "components/suggestions/suggestions_utils.h" |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 36 | #include "content/public/browser/browser_thread.h" |
[email protected] | 81e09e7 | 2014-05-07 13:41:22 | [diff] [blame] | 37 | #include "content/public/browser/url_data_source.h" |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 38 | #include "jni/MostVisitedSites_jni.h" |
| 39 | #include "third_party/skia/include/core/SkBitmap.h" |
| 40 | #include "ui/gfx/android/java_bitmap.h" |
| 41 | #include "ui/gfx/codec/jpeg_codec.h" |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 42 | #include "url/gurl.h" |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 43 | |
| 44 | using base::android::AttachCurrentThread; |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 45 | using base::android::ConvertJavaStringToUTF8; |
| 46 | using base::android::ScopedJavaGlobalRef; |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 47 | using base::android::ScopedJavaLocalRef; |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 48 | using base::android::ToJavaArrayOfStrings; |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 49 | using content::BrowserThread; |
| 50 | using history::TopSites; |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 51 | using suggestions::ChromeSuggestion; |
| 52 | using suggestions::SuggestionsProfile; |
| 53 | using suggestions::SuggestionsService; |
| 54 | using suggestions::SuggestionsServiceFactory; |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 55 | using suggestions::SyncState; |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 56 | |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 57 | namespace { |
| 58 | |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 59 | // Total number of tiles displayed. |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 60 | const char kNumTilesHistogramName[] = "NewTabPage.NumberOfTiles"; |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 61 | // Tracking thumbnails. |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 62 | const char kNumLocalThumbnailTilesHistogramName[] = |
| 63 | "NewTabPage.NumberOfThumbnailTiles"; |
| 64 | const char kNumEmptyTilesHistogramName[] = "NewTabPage.NumberOfGrayTiles"; |
| 65 | const char kNumServerTilesHistogramName[] = "NewTabPage.NumberOfExternalTiles"; |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 66 | |
| 67 | // Format for tile clicks histogram. |
| 68 | const char kOpenedItemHistogramFormat[] = "NewTabPage.MostVisited.%s"; |
| 69 | // Format for tile impressions histogram. |
| 70 | const char kImpressionHistogramFormat[] = "NewTabPage.SuggestionsImpression.%s"; |
| 71 | // Identifiers for the various tile sources. |
| 72 | const char kHistogramClientName[] = "client"; |
| 73 | const char kHistogramServerName[] = "server"; |
| 74 | const char kHistogramServerFormat[] = "server%d"; |
| 75 | const char kHistogramPopularName[] = "popular"; |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 76 | |
treib | 508939a | 2015-08-25 10:07:56 | [diff] [blame] | 77 | const char kPopularSitesFieldTrialName[] = "NTPPopularSites"; |
| 78 | |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 79 | scoped_ptr<SkBitmap> MaybeFetchLocalThumbnail( |
| 80 | const GURL& url, |
| 81 | const scoped_refptr<TopSites>& top_sites) { |
| 82 | DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 83 | scoped_refptr<base::RefCountedMemory> image; |
| 84 | scoped_ptr<SkBitmap> bitmap; |
| 85 | if (top_sites && top_sites->GetPageThumbnail(url, false, &image)) |
| 86 | bitmap.reset(gfx::JPEGCodec::Decode(image->front(), image->size())); |
| 87 | return bitmap.Pass(); |
[email protected] | d33adb40d | 2014-06-03 21:38:46 | [diff] [blame] | 88 | } |
| 89 | |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 90 | // Log an event for a given |histogram| at a given element |position|. This |
| 91 | // routine exists because regular histogram macros are cached thus can't be used |
| 92 | // if the name of the histogram will change at a given call site. |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 93 | void LogHistogramEvent(const std::string& histogram, |
| 94 | int position, |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 95 | int num_sites) { |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 96 | base::HistogramBase* counter = base::LinearHistogram::FactoryGet( |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 97 | histogram, |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 98 | 1, |
| 99 | num_sites, |
| 100 | num_sites + 1, |
| 101 | base::Histogram::kUmaTargetedHistogramFlag); |
[email protected] | 6f67448 | 2014-08-11 22:50:49 | [diff] [blame] | 102 | if (counter) |
| 103 | counter->Add(position); |
[email protected] | 9ed2f5c | 2014-06-13 14:55:24 | [diff] [blame] | 104 | } |
| 105 | |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 106 | // Return the current SyncState for use with the SuggestionsService. |
| 107 | SyncState GetSyncState(Profile* profile) { |
| 108 | ProfileSyncService* sync = |
| 109 | ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); |
| 110 | if (!sync) |
| 111 | return SyncState::SYNC_OR_HISTORY_SYNC_DISABLED; |
| 112 | return suggestions::GetSyncState( |
maxbogue | 96b7d27 | 2015-06-16 02:59:58 | [diff] [blame] | 113 | sync->CanSyncStart(), |
maxbogue | 192b360 | 2015-06-04 00:33:55 | [diff] [blame] | 114 | sync->IsSyncActive() && sync->ConfigurationDone(), |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 115 | sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES)); |
| 116 | } |
| 117 | |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 118 | bool ShouldShowPopularSites() { |
| 119 | // Note: It's important to query the field trial state first, to ensure that |
| 120 | // UMA reports the correct group. |
| 121 | const std::string group_name = |
treib | 508939a | 2015-08-25 10:07:56 | [diff] [blame] | 122 | base::FieldTrialList::FindFullName(kPopularSitesFieldTrialName); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 123 | base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 124 | if (cmd_line->HasSwitch(switches::kDisableNTPPopularSites)) |
| 125 | return false; |
| 126 | if (cmd_line->HasSwitch(switches::kEnableNTPPopularSites)) |
| 127 | return true; |
treib | eba6cee | 2015-09-09 13:25:59 | [diff] [blame] | 128 | return base::StartsWith(group_name, "Enabled", |
| 129 | base::CompareCase::INSENSITIVE_ASCII); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 130 | } |
| 131 | |
treib | 508939a | 2015-08-25 10:07:56 | [diff] [blame] | 132 | std::string GetPopularSitesFilename() { |
| 133 | return variations::GetVariationParamValue(kPopularSitesFieldTrialName, |
| 134 | "filename"); |
| 135 | } |
| 136 | |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 137 | } // namespace |
| 138 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 139 | MostVisitedSites::Suggestion::Suggestion(const base::string16& title, |
| 140 | const std::string& url, |
| 141 | MostVisitedSource source) |
| 142 | : title(title), url(url), source(source), provider_index(-1) {} |
| 143 | |
| 144 | MostVisitedSites::Suggestion::Suggestion(const base::string16& title, |
| 145 | const GURL& url, |
| 146 | MostVisitedSource source) |
| 147 | : title(title), url(url), source(source), provider_index(-1) {} |
| 148 | |
| 149 | MostVisitedSites::Suggestion::Suggestion(const base::string16& title, |
| 150 | const std::string& url, |
| 151 | MostVisitedSource source, |
| 152 | int provider_index) |
| 153 | : title(title), url(url), source(source), provider_index(provider_index) { |
| 154 | DCHECK_EQ(MostVisitedSites::SUGGESTIONS_SERVICE, source); |
| 155 | } |
| 156 | |
| 157 | MostVisitedSites::Suggestion::~Suggestion() {} |
| 158 | |
| 159 | std::string MostVisitedSites::Suggestion::GetSourceHistogramName() const { |
| 160 | switch (source) { |
| 161 | case MostVisitedSites::TOP_SITES: |
| 162 | return kHistogramClientName; |
| 163 | case MostVisitedSites::POPULAR: |
| 164 | return kHistogramPopularName; |
| 165 | case MostVisitedSites::SUGGESTIONS_SERVICE: |
| 166 | return provider_index >= 0 |
| 167 | ? base::StringPrintf(kHistogramServerFormat, provider_index) |
| 168 | : kHistogramServerName; |
| 169 | } |
| 170 | NOTREACHED(); |
| 171 | return std::string(); |
| 172 | } |
| 173 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 174 | MostVisitedSites::MostVisitedSites(Profile* profile) |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 175 | : profile_(profile), num_sites_(0), received_most_visited_sites_(false), |
| 176 | received_popular_sites_(false), recorded_uma_(false), |
mathp | d91e8eb | 2015-03-24 17:37:47 | [diff] [blame] | 177 | num_local_thumbs_(0), num_server_thumbs_(0), num_empty_thumbs_(0), |
| 178 | scoped_observer_(this), weak_ptr_factory_(this) { |
[email protected] | 81e09e7 | 2014-05-07 13:41:22 | [diff] [blame] | 179 | // Register the debugging page for the Suggestions Service and the thumbnails |
| 180 | // debugging page. |
| 181 | content::URLDataSource::Add(profile_, |
| 182 | new suggestions::SuggestionsSource(profile_)); |
| 183 | content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_)); |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 184 | |
| 185 | // Register this class as an observer to the sync service. It is important to |
| 186 | // be notified of changes in the sync state such as initialization, sync |
| 187 | // being enabled or disabled, etc. |
| 188 | ProfileSyncService* profile_sync_service = |
| 189 | ProfileSyncServiceFactory::GetForProfile(profile_); |
| 190 | if (profile_sync_service) |
| 191 | profile_sync_service->AddObserver(this); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 192 | |
| 193 | if (ShouldShowPopularSites()) { |
| 194 | popular_sites_.reset(new PopularSites( |
maybelle | a18d7d0 | 2015-09-08 14:28:25 | [diff] [blame] | 195 | profile, |
treib | 508939a | 2015-08-25 10:07:56 | [diff] [blame] | 196 | GetPopularSitesFilename(), |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 197 | profile_->GetRequestContext(), |
| 198 | base::Bind(&MostVisitedSites::OnPopularSitesAvailable, |
| 199 | base::Unretained(this)))); |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 200 | } else { |
| 201 | received_popular_sites_ = true; |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 202 | } |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 203 | } |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 204 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 205 | MostVisitedSites::~MostVisitedSites() { |
feng | 94a4210 | 2014-08-26 23:42:39 | [diff] [blame] | 206 | ProfileSyncService* profile_sync_service = |
| 207 | ProfileSyncServiceFactory::GetForProfile(profile_); |
| 208 | if (profile_sync_service && profile_sync_service->HasObserver(this)) |
| 209 | profile_sync_service->RemoveObserver(this); |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 210 | } |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 211 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 212 | void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) { |
| 213 | delete this; |
| 214 | } |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 215 | |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 216 | void MostVisitedSites::OnLoadingComplete(JNIEnv* env, jobject obj) { |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 217 | RecordThumbnailUMAMetrics(); |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 218 | } |
| 219 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 220 | void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env, |
| 221 | jobject obj, |
| 222 | jobject j_observer, |
| 223 | jint num_sites) { |
| 224 | observer_.Reset(env, j_observer); |
| 225 | num_sites_ = num_sites; |
[email protected] | 852fc79 | 2013-10-04 04:15:12 | [diff] [blame] | 226 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 227 | QueryMostVisitedURLs(); |
| 228 | |
jitendra.ks | 30f0339 | 2015-01-28 09:47:18 | [diff] [blame] | 229 | scoped_refptr<history::TopSites> top_sites = |
| 230 | TopSitesFactory::GetForProfile(profile_); |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 231 | if (top_sites) { |
| 232 | // TopSites updates itself after a delay. To ensure up-to-date results, |
| 233 | // force an update now. |
| 234 | top_sites->SyncWithHistory(); |
| 235 | |
sdefresne | edf9e01f | 2015-01-13 19:45:41 | [diff] [blame] | 236 | // Register as TopSitesObserver so that we can update ourselves when the |
| 237 | // TopSites changes. |
jitendra.ks | 30f0339 | 2015-01-28 09:47:18 | [diff] [blame] | 238 | scoped_observer_.Add(top_sites.get()); |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 239 | } |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 240 | } |
| 241 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 242 | void MostVisitedSites::GetURLThumbnail(JNIEnv* env, |
| 243 | jobject obj, |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 244 | jstring j_url, |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 245 | jobject j_callback_obj) { |
mostynb | 351bf98 | 2015-03-25 22:26:58 | [diff] [blame] | 246 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 247 | scoped_ptr<ScopedJavaGlobalRef<jobject>> j_callback( |
| 248 | new ScopedJavaGlobalRef<jobject>()); |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 249 | j_callback->Reset(env, j_callback_obj); |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 250 | |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 251 | GURL url(ConvertJavaStringToUTF8(env, j_url)); |
jitendra.ks | 30f0339 | 2015-01-28 09:47:18 | [diff] [blame] | 252 | scoped_refptr<TopSites> top_sites(TopSitesFactory::GetForProfile(profile_)); |
[email protected] | d33adb40d | 2014-06-03 21:38:46 | [diff] [blame] | 253 | |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 254 | BrowserThread::PostTaskAndReplyWithResult( |
[email protected] | d33adb40d | 2014-06-03 21:38:46 | [diff] [blame] | 255 | BrowserThread::DB, FROM_HERE, |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 256 | base::Bind(&MaybeFetchLocalThumbnail, url, top_sites), |
| 257 | base::Bind(&MostVisitedSites::OnLocalThumbnailFetched, |
| 258 | weak_ptr_factory_.GetWeakPtr(), url, |
| 259 | base::Passed(&j_callback))); |
| 260 | } |
| 261 | |
| 262 | void MostVisitedSites::OnLocalThumbnailFetched( |
| 263 | const GURL& url, |
| 264 | scoped_ptr<ScopedJavaGlobalRef<jobject>> j_callback, |
| 265 | scoped_ptr<SkBitmap> bitmap) { |
| 266 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 267 | if (!bitmap.get()) { |
| 268 | // A thumbnail is not locally available for |url|. Make sure it is put in |
| 269 | // the list to be fetched at the next visit to this site. |
| 270 | scoped_refptr<TopSites> top_sites(TopSitesFactory::GetForProfile(profile_)); |
| 271 | if (top_sites) |
| 272 | top_sites->AddForcedURL(url, base::Time::Now()); |
treib | ac5372f | 2015-09-09 09:08:22 | [diff] [blame] | 273 | // Also fetch a remote thumbnail if possible. PopularSites or the |
| 274 | // SuggestionsService can supply a thumbnail download URL. |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 275 | SuggestionsService* suggestions_service = |
treib | ac5372f | 2015-09-09 09:08:22 | [diff] [blame] | 276 | SuggestionsServiceFactory::GetForProfile(profile_); |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 277 | if (suggestions_service) { |
treib | ac5372f | 2015-09-09 09:08:22 | [diff] [blame] | 278 | if (popular_sites_) { |
| 279 | const std::vector<PopularSites::Site>& sites = popular_sites_->sites(); |
| 280 | auto it = std::find_if(sites.begin(), sites.end(), |
| 281 | [&url](const PopularSites::Site& site) { |
| 282 | return site.url == url; |
| 283 | }); |
| 284 | if (it != sites.end() && it->thumbnail_url.is_valid()) { |
| 285 | return suggestions_service->GetPageThumbnailWithURL( |
| 286 | url, it->thumbnail_url, |
| 287 | base::Bind(&MostVisitedSites::OnObtainedThumbnail, |
| 288 | weak_ptr_factory_.GetWeakPtr(), false, |
| 289 | base::Passed(&j_callback))); |
| 290 | } |
| 291 | } |
| 292 | if (mv_source_ == SUGGESTIONS_SERVICE) { |
| 293 | return suggestions_service->GetPageThumbnail( |
| 294 | url, base::Bind(&MostVisitedSites::OnObtainedThumbnail, |
| 295 | weak_ptr_factory_.GetWeakPtr(), false, |
| 296 | base::Passed(&j_callback))); |
| 297 | } |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 298 | } |
| 299 | } |
| 300 | OnObtainedThumbnail(true, j_callback.Pass(), url, bitmap.get()); |
| 301 | } |
| 302 | |
| 303 | void MostVisitedSites::OnObtainedThumbnail( |
| 304 | bool is_local_thumbnail, |
| 305 | scoped_ptr<ScopedJavaGlobalRef<jobject>> j_callback, |
| 306 | const GURL& url, |
| 307 | const SkBitmap* bitmap) { |
| 308 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 309 | JNIEnv* env = AttachCurrentThread(); |
| 310 | ScopedJavaLocalRef<jobject> j_bitmap; |
| 311 | if (bitmap) { |
| 312 | j_bitmap = gfx::ConvertToJavaBitmap(bitmap); |
| 313 | if (is_local_thumbnail) { |
| 314 | ++num_local_thumbs_; |
| 315 | } else { |
| 316 | ++num_server_thumbs_; |
| 317 | } |
| 318 | } else { |
| 319 | ++num_empty_thumbs_; |
| 320 | } |
| 321 | Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable( |
| 322 | env, j_callback->obj(), j_bitmap.obj()); |
[email protected] | c764b282 | 2013-07-03 04:16:48 | [diff] [blame] | 323 | } |
[email protected] | a4c2f28 | 2013-07-20 05:26:05 | [diff] [blame] | 324 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 325 | void MostVisitedSites::BlacklistUrl(JNIEnv* env, |
| 326 | jobject obj, |
| 327 | jstring j_url) { |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 328 | GURL url(ConvertJavaStringToUTF8(env, j_url)); |
[email protected] | a4c2f28 | 2013-07-20 05:26:05 | [diff] [blame] | 329 | |
treib | fac7519 | 2015-08-17 13:21:24 | [diff] [blame] | 330 | // Always blacklist in the local TopSites. |
| 331 | scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_); |
| 332 | if (top_sites) |
| 333 | top_sites->AddBlacklistedURL(url); |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 334 | |
treib | fac7519 | 2015-08-17 13:21:24 | [diff] [blame] | 335 | // Only blacklist in the server-side suggestions service if it's active. |
| 336 | if (mv_source_ == SUGGESTIONS_SERVICE) { |
| 337 | SuggestionsService* suggestions_service = |
| 338 | SuggestionsServiceFactory::GetForProfile(profile_); |
| 339 | DCHECK(suggestions_service); |
| 340 | suggestions_service->BlacklistURL( |
| 341 | url, base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, |
| 342 | weak_ptr_factory_.GetWeakPtr()), |
| 343 | base::Closure()); |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 344 | } |
[email protected] | a4c2f28 | 2013-07-20 05:26:05 | [diff] [blame] | 345 | } |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 346 | |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 347 | void MostVisitedSites::RecordOpenedMostVisitedItem(JNIEnv* env, |
| 348 | jobject obj, |
| 349 | jint index) { |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 350 | DCHECK_GE(index, 0); |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 351 | DCHECK_LT(index, static_cast<int>(current_suggestions_.size())); |
| 352 | std::string histogram = base::StringPrintf( |
| 353 | kOpenedItemHistogramFormat, |
| 354 | current_suggestions_[index]->GetSourceHistogramName().c_str()); |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 355 | LogHistogramEvent(histogram, index, num_sites_); |
[email protected] | 92a59882 | 2014-06-17 10:25:56 | [diff] [blame] | 356 | } |
| 357 | |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 358 | void MostVisitedSites::OnStateChanged() { |
| 359 | // There have been changes to the sync state. This class cares about a few |
| 360 | // (just initialized, enabled/disabled or history sync state changed). Re-run |
| 361 | // the query code which will use the proper state. |
| 362 | QueryMostVisitedURLs(); |
| 363 | } |
| 364 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 365 | // static |
| 366 | bool MostVisitedSites::Register(JNIEnv* env) { |
| 367 | return RegisterNativesImpl(env); |
| 368 | } |
| 369 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 370 | // static |
| 371 | void MostVisitedSites::RegisterProfilePrefs( |
| 372 | user_prefs::PrefRegistrySyncable* registry) { |
| 373 | registry->RegisterListPref(prefs::kNTPSuggestionsURL); |
| 374 | registry->RegisterListPref(prefs::kNTPSuggestionsIsPersonal); |
| 375 | } |
| 376 | |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 377 | void MostVisitedSites::QueryMostVisitedURLs() { |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 378 | SuggestionsService* suggestions_service = |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 379 | SuggestionsServiceFactory::GetForProfile(profile_); |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 380 | if (suggestions_service) { |
| 381 | // Suggestions service is enabled, initiate a query. |
| 382 | suggestions_service->FetchSuggestionsData( |
[email protected] | 1d1ab15 | 2014-08-21 17:14:12 | [diff] [blame] | 383 | GetSyncState(profile_), |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 384 | base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, |
| 385 | weak_ptr_factory_.GetWeakPtr())); |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 386 | } else { |
| 387 | InitiateTopSitesQuery(); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | void MostVisitedSites::InitiateTopSitesQuery() { |
jitendra.ks | 30f0339 | 2015-01-28 09:47:18 | [diff] [blame] | 392 | scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_); |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 393 | if (!top_sites) |
| 394 | return; |
| 395 | |
| 396 | top_sites->GetMostVisitedURLs( |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 397 | base::Bind(&MostVisitedSites::OnMostVisitedURLsAvailable, |
| 398 | weak_ptr_factory_.GetWeakPtr()), |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 399 | false); |
| 400 | } |
| 401 | |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 402 | void MostVisitedSites::OnMostVisitedURLsAvailable( |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 403 | const history::MostVisitedURLList& visited_list) { |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 404 | ScopedVector<Suggestion> suggestions; |
| 405 | size_t num_tiles = |
| 406 | std::min(visited_list.size(), static_cast<size_t>(num_sites_)); |
| 407 | for (size_t i = 0; i < num_tiles; ++i) { |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 408 | const history::MostVisitedURL& visited = visited_list[i]; |
| 409 | if (visited.url.is_empty()) { |
| 410 | num_tiles = i; |
| 411 | break; // This is the signal that there are no more real visited sites. |
| 412 | } |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 413 | suggestions.push_back( |
| 414 | new Suggestion(visited.title, visited.url.spec(), TOP_SITES)); |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 415 | } |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 416 | |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 417 | received_most_visited_sites_ = true; |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 418 | mv_source_ = TOP_SITES; |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 419 | AddPopularSites(&suggestions); |
| 420 | NotifyMostVisitedURLsObserver(); |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 421 | } |
| 422 | |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 423 | void MostVisitedSites::OnSuggestionsProfileAvailable( |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 424 | const SuggestionsProfile& suggestions_profile) { |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 425 | int num_tiles = suggestions_profile.suggestions_size(); |
mathp | d91e8eb | 2015-03-24 17:37:47 | [diff] [blame] | 426 | // With no server suggestions, fall back to local Most Visited. |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 427 | if (num_tiles == 0) { |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 428 | InitiateTopSitesQuery(); |
| 429 | return; |
| 430 | } |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 431 | if (num_sites_ < num_tiles) |
| 432 | num_tiles = num_sites_; |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 433 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 434 | ScopedVector<Suggestion> suggestions; |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 435 | for (int i = 0; i < num_tiles; ++i) { |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 436 | const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 437 | suggestions.push_back(new Suggestion( |
| 438 | base::UTF8ToUTF16(suggestion.title()), suggestion.url(), |
| 439 | SUGGESTIONS_SERVICE, |
| 440 | suggestion.providers_size() > 0 ? suggestion.providers(0) : -1)); |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 441 | } |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 442 | |
| 443 | received_most_visited_sites_ = true; |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 444 | mv_source_ = SUGGESTIONS_SERVICE; |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 445 | AddPopularSites(&suggestions); |
| 446 | NotifyMostVisitedURLsObserver(); |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 447 | } |
[email protected] | d497524 | 2014-06-02 18:16:20 | [diff] [blame] | 448 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 449 | void MostVisitedSites::AddPopularSites( |
| 450 | ScopedVector<Suggestion>* personal_suggestions) { |
| 451 | size_t num_personal_suggestions = personal_suggestions->size(); |
| 452 | DCHECK_LE(num_personal_suggestions, static_cast<size_t>(num_sites_)); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 453 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 454 | // Collect non-blacklisted popular suggestions, skipping those already present |
| 455 | // in the personal suggestions. |
| 456 | size_t num_popular_suggestions = num_sites_ - num_personal_suggestions; |
| 457 | ScopedVector<Suggestion> popular_suggestions; |
| 458 | popular_suggestions.reserve(num_popular_suggestions); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 459 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 460 | if (num_popular_suggestions > 0 && popular_sites_) { |
| 461 | std::set<std::string> personal_hosts; |
| 462 | for (const Suggestion* suggestion : *personal_suggestions) |
| 463 | personal_hosts.insert(suggestion->url.host()); |
| 464 | scoped_refptr<TopSites> top_sites(TopSitesFactory::GetForProfile(profile_)); |
| 465 | for (const PopularSites::Site& popular_site : popular_sites_->sites()) { |
| 466 | // Skip blacklisted sites. |
| 467 | if (top_sites && top_sites->IsBlacklisted(popular_site.url)) |
| 468 | continue; |
| 469 | std::string host = popular_site.url.host(); |
| 470 | // Skip suggestions already present in personal. |
| 471 | if (personal_hosts.find(host) != personal_hosts.end()) |
| 472 | continue; |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 473 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 474 | popular_suggestions.push_back( |
| 475 | new Suggestion(popular_site.title, popular_site.url, POPULAR)); |
| 476 | if (popular_suggestions.size() >= num_popular_suggestions) |
| 477 | break; |
| 478 | } |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 479 | } |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 480 | num_popular_suggestions = popular_suggestions.size(); |
| 481 | size_t num_actual_tiles = num_personal_suggestions + num_popular_suggestions; |
| 482 | std::vector<std::string> old_sites_url; |
| 483 | std::vector<bool> old_sites_is_personal; |
| 484 | GetPreviousNTPSites(num_actual_tiles, &old_sites_url, &old_sites_is_personal); |
| 485 | ScopedVector<Suggestion> merged_suggestions = |
| 486 | MergeSuggestions(personal_suggestions, &popular_suggestions, |
| 487 | old_sites_url, old_sites_is_personal); |
| 488 | DCHECK_EQ(num_actual_tiles, merged_suggestions.size()); |
| 489 | current_suggestions_.swap(merged_suggestions); |
| 490 | if (received_popular_sites_) |
| 491 | SaveCurrentNTPSites(); |
treib | cf674e6 | 2015-08-17 15:43:01 | [diff] [blame] | 492 | } |
| 493 | |
| 494 | // static |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 495 | ScopedVector<MostVisitedSites::Suggestion> MostVisitedSites::MergeSuggestions( |
| 496 | ScopedVector<Suggestion>* personal_suggestions, |
| 497 | ScopedVector<Suggestion>* popular_suggestions, |
| 498 | const std::vector<std::string>& old_sites_url, |
| 499 | const std::vector<bool>& old_sites_is_personal) { |
| 500 | size_t num_personal_suggestions = personal_suggestions->size(); |
| 501 | size_t num_popular_suggestions = popular_suggestions->size(); |
| 502 | size_t num_tiles = num_popular_suggestions + num_personal_suggestions; |
| 503 | ScopedVector<Suggestion> merged_suggestions; |
| 504 | merged_suggestions.resize(num_tiles); |
treib | cf674e6 | 2015-08-17 15:43:01 | [diff] [blame] | 505 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 506 | size_t num_old_tiles = old_sites_url.size(); |
| 507 | DCHECK_LE(num_old_tiles, num_tiles); |
| 508 | DCHECK_EQ(num_old_tiles, old_sites_is_personal.size()); |
| 509 | std::vector<std::string> old_sites_host; |
| 510 | old_sites_host.reserve(num_old_tiles); |
| 511 | // Only populate the hosts for popular suggestions as only they can be |
| 512 | // replaced by host. Personal suggestions require an exact url match to be |
| 513 | // replaced. |
| 514 | for (size_t i = 0; i < num_old_tiles; ++i) { |
| 515 | old_sites_host.push_back(old_sites_is_personal[i] |
| 516 | ? std::string() |
| 517 | : GURL(old_sites_url[i]).host()); |
treib | cf674e6 | 2015-08-17 15:43:01 | [diff] [blame] | 518 | } |
| 519 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 520 | // Insert personal suggestions if they existed previously. |
| 521 | std::vector<size_t> new_personal_suggestions = InsertMatchingSuggestions( |
| 522 | personal_suggestions, &merged_suggestions, old_sites_url, old_sites_host); |
| 523 | // Insert popular suggestions if they existed previously. |
| 524 | std::vector<size_t> new_popular_suggestions = InsertMatchingSuggestions( |
| 525 | popular_suggestions, &merged_suggestions, old_sites_url, old_sites_host); |
| 526 | // Insert leftover personal suggestions. |
| 527 | size_t filled_so_far = InsertAllSuggestions( |
| 528 | 0, new_personal_suggestions, personal_suggestions, &merged_suggestions); |
| 529 | // Insert leftover popular suggestions. |
| 530 | InsertAllSuggestions(filled_so_far, new_popular_suggestions, |
| 531 | popular_suggestions, &merged_suggestions); |
| 532 | return merged_suggestions.Pass(); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 533 | } |
| 534 | |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 535 | void MostVisitedSites::GetPreviousNTPSites( |
| 536 | size_t num_tiles, |
| 537 | std::vector<std::string>* old_sites_url, |
| 538 | std::vector<bool>* old_sites_is_personal) const { |
| 539 | const PrefService* prefs = profile_->GetPrefs(); |
| 540 | const base::ListValue* url_list = prefs->GetList(prefs::kNTPSuggestionsURL); |
| 541 | const base::ListValue* source_list = |
| 542 | prefs->GetList(prefs::kNTPSuggestionsIsPersonal); |
| 543 | DCHECK_EQ(url_list->GetSize(), source_list->GetSize()); |
| 544 | if (url_list->GetSize() < num_tiles) |
| 545 | num_tiles = url_list->GetSize(); |
| 546 | if (num_tiles == 0) { |
| 547 | // No fallback required as Personal suggestions take precedence anyway. |
| 548 | return; |
| 549 | } |
| 550 | old_sites_url->reserve(num_tiles); |
| 551 | old_sites_is_personal->reserve(num_tiles); |
| 552 | for (size_t i = 0; i < num_tiles; ++i) { |
| 553 | std::string url_string; |
| 554 | bool success = url_list->GetString(i, &url_string); |
| 555 | DCHECK(success); |
| 556 | old_sites_url->push_back(url_string); |
| 557 | bool is_personal; |
| 558 | success = source_list->GetBoolean(i, &is_personal); |
| 559 | DCHECK(success); |
| 560 | old_sites_is_personal->push_back(is_personal); |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | void MostVisitedSites::SaveCurrentNTPSites() { |
| 565 | base::ListValue url_list; |
| 566 | base::ListValue source_list; |
| 567 | for (const Suggestion* suggestion : current_suggestions_) { |
| 568 | url_list.AppendString(suggestion->url.spec()); |
| 569 | source_list.AppendBoolean(suggestion->source != MostVisitedSites::POPULAR); |
| 570 | } |
| 571 | PrefService* prefs = profile_->GetPrefs(); |
| 572 | prefs->Set(prefs::kNTPSuggestionsIsPersonal, source_list); |
| 573 | prefs->Set(prefs::kNTPSuggestionsURL, url_list); |
| 574 | } |
| 575 | |
| 576 | // static |
| 577 | std::vector<size_t> MostVisitedSites::InsertMatchingSuggestions( |
| 578 | ScopedVector<Suggestion>* src_suggestions, |
| 579 | ScopedVector<Suggestion>* dst_suggestions, |
| 580 | const std::vector<std::string>& match_urls, |
| 581 | const std::vector<std::string>& match_hosts) { |
| 582 | std::vector<size_t> unmatched_suggestions; |
| 583 | size_t num_src_suggestions = src_suggestions->size(); |
| 584 | size_t num_matchers = match_urls.size(); |
| 585 | for (size_t i = 0; i < num_src_suggestions; ++i) { |
| 586 | size_t position; |
| 587 | for (position = 0; position < num_matchers; ++position) { |
| 588 | if ((*dst_suggestions)[position] != nullptr) |
| 589 | continue; |
| 590 | if (match_urls[position] == (*src_suggestions)[i]->url.spec()) |
| 591 | break; |
| 592 | // match_hosts is only populated for suggestions which can be replaced by |
| 593 | // host matching like popular suggestions. |
| 594 | if (match_hosts[position] == (*src_suggestions)[i]->url.host()) |
| 595 | break; |
| 596 | } |
| 597 | if (position == num_matchers) { |
| 598 | unmatched_suggestions.push_back(i); |
| 599 | } else { |
| 600 | // A move is required as the source and destination containers own the |
| 601 | // elements. |
| 602 | std::swap((*dst_suggestions)[position], (*src_suggestions)[i]); |
| 603 | } |
| 604 | } |
| 605 | return unmatched_suggestions; |
| 606 | } |
| 607 | |
| 608 | // static |
| 609 | size_t MostVisitedSites::InsertAllSuggestions( |
| 610 | size_t start_position, |
| 611 | const std::vector<size_t>& insert_positions, |
| 612 | ScopedVector<Suggestion>* src_suggestions, |
| 613 | ScopedVector<Suggestion>* dst_suggestions) { |
| 614 | size_t num_inserts = insert_positions.size(); |
| 615 | size_t num_dests = dst_suggestions->size(); |
| 616 | |
| 617 | size_t src_pos = 0; |
| 618 | size_t i = start_position; |
| 619 | for (; i < num_dests && src_pos < num_inserts; ++i) { |
| 620 | if ((*dst_suggestions)[i] != nullptr) |
| 621 | continue; |
| 622 | size_t src = insert_positions[src_pos++]; |
| 623 | std::swap((*dst_suggestions)[i], (*src_suggestions)[src]); |
| 624 | } |
| 625 | // Return destination postions filled so far which becomes the start_position |
| 626 | // for future runs. |
| 627 | return i; |
| 628 | } |
| 629 | |
| 630 | void MostVisitedSites::NotifyMostVisitedURLsObserver() { |
| 631 | size_t num_suggestions = current_suggestions_.size(); |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 632 | if (received_most_visited_sites_ && received_popular_sites_ && |
| 633 | !recorded_uma_) { |
| 634 | RecordImpressionUMAMetrics(); |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 635 | UMA_HISTOGRAM_SPARSE_SLOWLY(kNumTilesHistogramName, num_suggestions); |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 636 | recorded_uma_ = true; |
| 637 | } |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 638 | std::vector<base::string16> titles; |
| 639 | std::vector<std::string> urls; |
| 640 | titles.reserve(num_suggestions); |
| 641 | urls.reserve(num_suggestions); |
| 642 | for (const Suggestion* suggestion : current_suggestions_) { |
| 643 | titles.push_back(suggestion->title); |
| 644 | urls.push_back(suggestion->url.spec()); |
| 645 | } |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 646 | JNIEnv* env = AttachCurrentThread(); |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 647 | DCHECK_EQ(titles.size(), urls.size()); |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 648 | Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable( |
knn | 6cf777fc | 2015-05-06 13:21:48 | [diff] [blame] | 649 | env, observer_.obj(), ToJavaArrayOfStrings(env, titles).obj(), |
[email protected] | bc093e8 | 2014-03-04 21:49:11 | [diff] [blame] | 650 | ToJavaArrayOfStrings(env, urls).obj()); |
| 651 | } |
| 652 | |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 653 | void MostVisitedSites::OnPopularSitesAvailable(bool success) { |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 654 | received_popular_sites_ = true; |
| 655 | |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 656 | if (!success) { |
| 657 | LOG(WARNING) << "Download of popular sites failed"; |
| 658 | return; |
| 659 | } |
| 660 | |
treib | 7f5cf87 | 2015-08-11 13:11:47 | [diff] [blame] | 661 | if (observer_.is_null()) |
| 662 | return; |
| 663 | |
| 664 | std::vector<std::string> urls; |
| 665 | std::vector<std::string> favicon_urls; |
| 666 | for (const PopularSites::Site& popular_site : popular_sites_->sites()) { |
| 667 | urls.push_back(popular_site.url.spec()); |
| 668 | favicon_urls.push_back(popular_site.favicon_url.spec()); |
| 669 | } |
| 670 | JNIEnv* env = AttachCurrentThread(); |
| 671 | Java_MostVisitedURLsObserver_onPopularURLsAvailable( |
| 672 | env, observer_.obj(), ToJavaArrayOfStrings(env, urls).obj(), |
| 673 | ToJavaArrayOfStrings(env, favicon_urls).obj()); |
| 674 | |
| 675 | QueryMostVisitedURLs(); |
treib | cffa650 | 2015-08-06 09:12:27 | [diff] [blame] | 676 | } |
| 677 | |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 678 | void MostVisitedSites::RecordThumbnailUMAMetrics() { |
[email protected] | 32809e9e | 2014-06-19 01:10:58 | [diff] [blame] | 679 | UMA_HISTOGRAM_SPARSE_SLOWLY(kNumLocalThumbnailTilesHistogramName, |
| 680 | num_local_thumbs_); |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 681 | num_local_thumbs_ = 0; |
[email protected] | 32809e9e | 2014-06-19 01:10:58 | [diff] [blame] | 682 | UMA_HISTOGRAM_SPARSE_SLOWLY(kNumEmptyTilesHistogramName, num_empty_thumbs_); |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 683 | num_empty_thumbs_ = 0; |
[email protected] | 32809e9e | 2014-06-19 01:10:58 | [diff] [blame] | 684 | UMA_HISTOGRAM_SPARSE_SLOWLY(kNumServerTilesHistogramName, num_server_thumbs_); |
[email protected] | 1d778e1 | 2014-06-17 02:28:51 | [diff] [blame] | 685 | num_server_thumbs_ = 0; |
| 686 | } |
| 687 | |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 688 | void MostVisitedSites::RecordImpressionUMAMetrics() { |
knn | cbbd754d | 2015-09-09 15:43:40 | [diff] [blame^] | 689 | for (size_t i = 0; i < current_suggestions_.size(); i++) { |
| 690 | std::string histogram = base::StringPrintf( |
| 691 | kImpressionHistogramFormat, |
| 692 | current_suggestions_[i]->GetSourceHistogramName().c_str()); |
treib | 783a337 | 2015-08-25 16:24:39 | [diff] [blame] | 693 | LogHistogramEvent(histogram, static_cast<int>(i), num_sites_); |
| 694 | } |
| 695 | } |
| 696 | |
sdefresne | edf9e01f | 2015-01-13 19:45:41 | [diff] [blame] | 697 | void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) { |
| 698 | } |
| 699 | |
fserb | db57511 | 2015-06-29 21:31:59 | [diff] [blame] | 700 | void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites, |
| 701 | ChangeReason change_reason) { |
sdefresne | edf9e01f | 2015-01-13 19:45:41 | [diff] [blame] | 702 | if (mv_source_ == TOP_SITES) { |
| 703 | // The displayed suggestions are invalidated. |
| 704 | QueryMostVisitedURLs(); |
| 705 | } |
| 706 | } |
| 707 | |
torne | 89cc5d9 | 2015-09-04 11:16:35 | [diff] [blame] | 708 | static jlong Init(JNIEnv* env, |
| 709 | const JavaParamRef<jobject>& obj, |
| 710 | const JavaParamRef<jobject>& jprofile) { |
[email protected] | 7ceb4e3 | 2013-12-06 04:13:04 | [diff] [blame] | 711 | MostVisitedSites* most_visited_sites = |
| 712 | new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile)); |
| 713 | return reinterpret_cast<intptr_t>(most_visited_sites); |
| 714 | } |