Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/most_visited_sites.h" | 5 #include "chrome/browser/android/most_visited_sites.h" |
| 6 | 6 |
| 7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_array.h" | 8 #include "base/android/jni_array.h" |
| 9 #include "base/android/jni_string.h" | 9 #include "base/android/jni_string.h" |
| 10 #include "base/android/scoped_java_ref.h" | 10 #include "base/android/scoped_java_ref.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 | 52 |
| 53 namespace { | 53 namespace { |
| 54 | 54 |
| 55 // Total number of tiles displayed. | 55 // Total number of tiles displayed. |
| 56 const char kNumTilesHistogramName[] = "NewTabPage.NumberOfTiles"; | 56 const char kNumTilesHistogramName[] = "NewTabPage.NumberOfTiles"; |
| 57 // Tracking thumbnails. | 57 // Tracking thumbnails. |
| 58 const char kNumLocalThumbnailTilesHistogramName[] = | 58 const char kNumLocalThumbnailTilesHistogramName[] = |
| 59 "NewTabPage.NumberOfThumbnailTiles"; | 59 "NewTabPage.NumberOfThumbnailTiles"; |
| 60 const char kNumEmptyTilesHistogramName[] = "NewTabPage.NumberOfGrayTiles"; | 60 const char kNumEmptyTilesHistogramName[] = "NewTabPage.NumberOfGrayTiles"; |
| 61 const char kNumServerTilesHistogramName[] = "NewTabPage.NumberOfExternalTiles"; | 61 const char kNumServerTilesHistogramName[] = "NewTabPage.NumberOfExternalTiles"; |
| 62 // Client suggestion opened. | 62 |
| 63 const char kOpenedItemClientHistogramName[] = "NewTabPage.MostVisited.client"; | 63 // Format for tile clicks histogram. |
| 64 // Server suggestion opened, no provider. | 64 const char kOpenedItemHistogramFormat[] = "NewTabPage.MostVisited.%s"; |
| 65 const char kOpenedItemServerHistogramName[] = "NewTabPage.MostVisited.server"; | 65 // Format for tile impressions histogram. |
| 66 // Server suggestion opened with provider. | 66 const char kImpressionHistogramFormat[] = "NewTabPage.SuggestionsImpression.%s"; |
| 67 const char kOpenedItemServerProviderHistogramFormat[] = | 67 // Identifiers for the various tile sources. |
| 68 "NewTabPage.MostVisited.server%d"; | 68 const char kHistogramClientName[] = "client"; |
| 69 // Client impression. | 69 const char kHistogramServerName[] = "server"; |
| 70 const char kImpressionClientHistogramName[] = | 70 const char kHistogramServerFormat[] = "server%d"; |
| 71 "NewTabPage.SuggestionsImpression.client"; | 71 const char kHistogramPopularName[] = "popular"; |
| 72 // Server suggestion impression, no provider. | |
| 73 const char kImpressionServerHistogramName[] = | |
| 74 "NewTabPage.SuggestionsImpression.server"; | |
| 75 // Server suggestion impression with provider. | |
| 76 const char kImpressionServerHistogramFormat[] = | |
| 77 "NewTabPage.SuggestionsImpression.server%d"; | |
| 78 | 72 |
| 79 const char kPopularSitesFieldTrialName[] = "NTPPopularSites"; | 73 const char kPopularSitesFieldTrialName[] = "NTPPopularSites"; |
| 80 | 74 |
| 81 scoped_ptr<SkBitmap> MaybeFetchLocalThumbnail( | 75 scoped_ptr<SkBitmap> MaybeFetchLocalThumbnail( |
| 82 const GURL& url, | 76 const GURL& url, |
| 83 const scoped_refptr<TopSites>& top_sites) { | 77 const scoped_refptr<TopSites>& top_sites) { |
| 84 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 78 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
| 85 scoped_refptr<base::RefCountedMemory> image; | 79 scoped_refptr<base::RefCountedMemory> image; |
| 86 scoped_ptr<SkBitmap> bitmap; | 80 scoped_ptr<SkBitmap> bitmap; |
| 87 if (top_sites && top_sites->GetPageThumbnail(url, false, &image)) | 81 if (top_sites && top_sites->GetPageThumbnail(url, false, &image)) |
| 88 bitmap.reset(gfx::JPEGCodec::Decode(image->front(), image->size())); | 82 bitmap.reset(gfx::JPEGCodec::Decode(image->front(), image->size())); |
| 89 return bitmap.Pass(); | 83 return bitmap.Pass(); |
| 90 } | 84 } |
| 91 | 85 |
| 92 // Log an event for a given |histogram| at a given element |position|. This | 86 // Log an event for a given |histogram| at a given element |position|. This |
| 93 // routine exists because regular histogram macros are cached thus can't be used | 87 // routine exists because regular histogram macros are cached thus can't be used |
| 94 // if the name of the histogram will change at a given call site. | 88 // if the name of the histogram will change at a given call site. |
| 95 void LogHistogramEvent(const std::string& histogram, int position, | 89 void LogHistogramEvent(const std::string& histogram, |
| 90 int position, | |
| 96 int num_sites) { | 91 int num_sites) { |
| 97 base::HistogramBase* counter = base::LinearHistogram::FactoryGet( | 92 base::HistogramBase* counter = base::LinearHistogram::FactoryGet( |
| 98 histogram, | 93 histogram, |
| 99 1, | 94 1, |
| 100 num_sites, | 95 num_sites, |
| 101 num_sites + 1, | 96 num_sites + 1, |
| 102 base::Histogram::kUmaTargetedHistogramFlag); | 97 base::Histogram::kUmaTargetedHistogramFlag); |
| 103 if (counter) | 98 if (counter) |
| 104 counter->Add(position); | 99 counter->Add(position); |
| 105 } | 100 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 130 } | 125 } |
| 131 | 126 |
| 132 std::string GetPopularSitesFilename() { | 127 std::string GetPopularSitesFilename() { |
| 133 return variations::GetVariationParamValue(kPopularSitesFieldTrialName, | 128 return variations::GetVariationParamValue(kPopularSitesFieldTrialName, |
| 134 "filename"); | 129 "filename"); |
| 135 } | 130 } |
| 136 | 131 |
| 137 } // namespace | 132 } // namespace |
| 138 | 133 |
| 139 MostVisitedSites::MostVisitedSites(Profile* profile) | 134 MostVisitedSites::MostVisitedSites(Profile* profile) |
| 140 : profile_(profile), num_sites_(0), initial_load_done_(false), | 135 : profile_(profile), num_sites_(0), received_most_visited_sites_(false), |
| 136 received_popular_sites_(false), recorded_uma_(false), | |
| 141 num_local_thumbs_(0), num_server_thumbs_(0), num_empty_thumbs_(0), | 137 num_local_thumbs_(0), num_server_thumbs_(0), num_empty_thumbs_(0), |
| 142 scoped_observer_(this), weak_ptr_factory_(this) { | 138 scoped_observer_(this), weak_ptr_factory_(this) { |
| 143 // Register the debugging page for the Suggestions Service and the thumbnails | 139 // Register the debugging page for the Suggestions Service and the thumbnails |
| 144 // debugging page. | 140 // debugging page. |
| 145 content::URLDataSource::Add(profile_, | 141 content::URLDataSource::Add(profile_, |
| 146 new suggestions::SuggestionsSource(profile_)); | 142 new suggestions::SuggestionsSource(profile_)); |
| 147 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_)); | 143 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_)); |
| 148 | 144 |
| 149 // Register this class as an observer to the sync service. It is important to | 145 // Register this class as an observer to the sync service. It is important to |
| 150 // be notified of changes in the sync state such as initialization, sync | 146 // be notified of changes in the sync state such as initialization, sync |
| 151 // being enabled or disabled, etc. | 147 // being enabled or disabled, etc. |
| 152 ProfileSyncService* profile_sync_service = | 148 ProfileSyncService* profile_sync_service = |
| 153 ProfileSyncServiceFactory::GetForProfile(profile_); | 149 ProfileSyncServiceFactory::GetForProfile(profile_); |
| 154 if (profile_sync_service) | 150 if (profile_sync_service) |
| 155 profile_sync_service->AddObserver(this); | 151 profile_sync_service->AddObserver(this); |
| 156 | 152 |
| 157 if (ShouldShowPopularSites()) { | 153 if (ShouldShowPopularSites()) { |
| 158 popular_sites_.reset(new PopularSites( | 154 popular_sites_.reset(new PopularSites( |
| 159 GetPopularSitesFilename(), | 155 GetPopularSitesFilename(), |
| 160 profile_->GetRequestContext(), | 156 profile_->GetRequestContext(), |
| 161 base::Bind(&MostVisitedSites::OnPopularSitesAvailable, | 157 base::Bind(&MostVisitedSites::OnPopularSitesAvailable, |
| 162 base::Unretained(this)))); | 158 base::Unretained(this)))); |
| 159 } else { | |
| 160 received_popular_sites_ = true; | |
| 163 } | 161 } |
| 164 } | 162 } |
| 165 | 163 |
| 166 MostVisitedSites::~MostVisitedSites() { | 164 MostVisitedSites::~MostVisitedSites() { |
| 167 ProfileSyncService* profile_sync_service = | 165 ProfileSyncService* profile_sync_service = |
| 168 ProfileSyncServiceFactory::GetForProfile(profile_); | 166 ProfileSyncServiceFactory::GetForProfile(profile_); |
| 169 if (profile_sync_service && profile_sync_service->HasObserver(this)) | 167 if (profile_sync_service && profile_sync_service->HasObserver(this)) |
| 170 profile_sync_service->RemoveObserver(this); | 168 profile_sync_service->RemoveObserver(this); |
| 171 } | 169 } |
| 172 | 170 |
| 173 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) { | 171 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) { |
| 174 delete this; | 172 delete this; |
| 175 } | 173 } |
| 176 | 174 |
| 177 void MostVisitedSites::OnLoadingComplete(JNIEnv* env, jobject obj) { | 175 void MostVisitedSites::OnLoadingComplete(JNIEnv* env, jobject obj) { |
| 178 RecordUMAMetrics(); | 176 RecordThumbnailUMAMetrics(); |
| 179 } | 177 } |
| 180 | 178 |
| 181 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env, | 179 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env, |
| 182 jobject obj, | 180 jobject obj, |
| 183 jobject j_observer, | 181 jobject j_observer, |
| 184 jint num_sites) { | 182 jint num_sites) { |
| 185 observer_.Reset(env, j_observer); | 183 observer_.Reset(env, j_observer); |
| 186 num_sites_ = num_sites; | 184 num_sites_ = num_sites; |
| 187 | 185 |
| 188 QueryMostVisitedURLs(); | 186 QueryMostVisitedURLs(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 suggestions_service->BlacklistURL( | 283 suggestions_service->BlacklistURL( |
| 286 url, base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, | 284 url, base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, |
| 287 weak_ptr_factory_.GetWeakPtr()), | 285 weak_ptr_factory_.GetWeakPtr()), |
| 288 base::Closure()); | 286 base::Closure()); |
| 289 } | 287 } |
| 290 } | 288 } |
| 291 | 289 |
| 292 void MostVisitedSites::RecordOpenedMostVisitedItem(JNIEnv* env, | 290 void MostVisitedSites::RecordOpenedMostVisitedItem(JNIEnv* env, |
| 293 jobject obj, | 291 jobject obj, |
| 294 jint index) { | 292 jint index) { |
| 295 switch (mv_source_) { | 293 std::string histogram = base::StringPrintf(kOpenedItemHistogramFormat, |
| 296 case TOP_SITES: { | 294 tile_sources_[index].c_str()); |
|
Alexei Svitkine (slow)
2015/08/25 15:01:19
Nit: Add a DCHECK() that index is within valid ran
Marc Treib
2015/08/25 15:19:32
Done.
| |
| 297 UMA_HISTOGRAM_SPARSE_SLOWLY(kOpenedItemClientHistogramName, index); | 295 LogHistogramEvent(histogram, index, num_sites_); |
| 298 break; | |
| 299 } | |
| 300 case SUGGESTIONS_SERVICE: { | |
| 301 if (server_suggestions_.suggestions_size() > index) { | |
| 302 if (server_suggestions_.suggestions(index).providers_size()) { | |
| 303 std::string histogram = base::StringPrintf( | |
| 304 kOpenedItemServerProviderHistogramFormat, | |
| 305 server_suggestions_.suggestions(index).providers(0)); | |
| 306 LogHistogramEvent(histogram, index, num_sites_); | |
| 307 } else { | |
| 308 UMA_HISTOGRAM_SPARSE_SLOWLY(kOpenedItemServerHistogramName, index); | |
| 309 } | |
| 310 } | |
| 311 break; | |
| 312 } | |
| 313 } | |
| 314 } | 296 } |
| 315 | 297 |
| 316 void MostVisitedSites::OnStateChanged() { | 298 void MostVisitedSites::OnStateChanged() { |
| 317 // There have been changes to the sync state. This class cares about a few | 299 // There have been changes to the sync state. This class cares about a few |
| 318 // (just initialized, enabled/disabled or history sync state changed). Re-run | 300 // (just initialized, enabled/disabled or history sync state changed). Re-run |
| 319 // the query code which will use the proper state. | 301 // the query code which will use the proper state. |
| 320 QueryMostVisitedURLs(); | 302 QueryMostVisitedURLs(); |
| 321 } | 303 } |
| 322 | 304 |
| 323 // static | 305 // static |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 347 top_sites->GetMostVisitedURLs( | 329 top_sites->GetMostVisitedURLs( |
| 348 base::Bind(&MostVisitedSites::OnMostVisitedURLsAvailable, | 330 base::Bind(&MostVisitedSites::OnMostVisitedURLsAvailable, |
| 349 weak_ptr_factory_.GetWeakPtr()), | 331 weak_ptr_factory_.GetWeakPtr()), |
| 350 false); | 332 false); |
| 351 } | 333 } |
| 352 | 334 |
| 353 void MostVisitedSites::OnMostVisitedURLsAvailable( | 335 void MostVisitedSites::OnMostVisitedURLsAvailable( |
| 354 const history::MostVisitedURLList& visited_list) { | 336 const history::MostVisitedURLList& visited_list) { |
| 355 std::vector<base::string16> titles; | 337 std::vector<base::string16> titles; |
| 356 std::vector<std::string> urls; | 338 std::vector<std::string> urls; |
| 339 tile_sources_.clear(); | |
| 357 int num_tiles = std::min(static_cast<int>(visited_list.size()), num_sites_); | 340 int num_tiles = std::min(static_cast<int>(visited_list.size()), num_sites_); |
| 358 for (int i = 0; i < num_tiles; ++i) { | 341 for (int i = 0; i < num_tiles; ++i) { |
| 359 const history::MostVisitedURL& visited = visited_list[i]; | 342 const history::MostVisitedURL& visited = visited_list[i]; |
| 360 if (visited.url.is_empty()) { | 343 if (visited.url.is_empty()) { |
| 361 num_tiles = i; | 344 num_tiles = i; |
| 362 break; // This is the signal that there are no more real visited sites. | 345 break; // This is the signal that there are no more real visited sites. |
| 363 } | 346 } |
| 364 titles.push_back(visited.title); | 347 titles.push_back(visited.title); |
| 365 urls.push_back(visited.url.spec()); | 348 urls.push_back(visited.url.spec()); |
| 349 tile_sources_.push_back(kHistogramClientName); | |
| 366 } | 350 } |
| 367 | 351 |
| 368 // Only log impression metrics on the initial load of the NTP. | 352 received_most_visited_sites_ = true; |
| 369 if (!initial_load_done_) { | |
| 370 for (int i = 0; i < num_tiles; ++i) { | |
| 371 UMA_HISTOGRAM_SPARSE_SLOWLY(kImpressionClientHistogramName, i); | |
| 372 } | |
| 373 } | |
| 374 mv_source_ = TOP_SITES; | 353 mv_source_ = TOP_SITES; |
| 375 AddPopularSites(&titles, &urls); | 354 AddPopularSites(&titles, &urls); |
| 376 NotifyMostVisitedURLsObserver(titles, urls); | 355 NotifyMostVisitedURLsObserver(titles, urls); |
| 377 } | 356 } |
| 378 | 357 |
| 379 void MostVisitedSites::OnSuggestionsProfileAvailable( | 358 void MostVisitedSites::OnSuggestionsProfileAvailable( |
| 380 const SuggestionsProfile& suggestions_profile) { | 359 const SuggestionsProfile& suggestions_profile) { |
| 381 int num_tiles = suggestions_profile.suggestions_size(); | 360 int num_tiles = suggestions_profile.suggestions_size(); |
| 382 // With no server suggestions, fall back to local Most Visited. | 361 // With no server suggestions, fall back to local Most Visited. |
| 383 if (num_tiles == 0) { | 362 if (num_tiles == 0) { |
| 384 InitiateTopSitesQuery(); | 363 InitiateTopSitesQuery(); |
| 385 return; | 364 return; |
| 386 } | 365 } |
| 387 if (num_sites_ < num_tiles) | 366 if (num_sites_ < num_tiles) |
| 388 num_tiles = num_sites_; | 367 num_tiles = num_sites_; |
| 389 | 368 |
| 390 std::vector<base::string16> titles; | 369 std::vector<base::string16> titles; |
| 391 std::vector<std::string> urls; | 370 std::vector<std::string> urls; |
| 371 tile_sources_.clear(); | |
| 392 for (int i = 0; i < num_tiles; ++i) { | 372 for (int i = 0; i < num_tiles; ++i) { |
| 393 const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); | 373 const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i); |
| 394 titles.push_back(base::UTF8ToUTF16(suggestion.title())); | 374 titles.push_back(base::UTF8ToUTF16(suggestion.title())); |
| 395 urls.push_back(suggestion.url()); | 375 urls.push_back(suggestion.url()); |
| 396 // Only log impression metrics on the initial NTP load. | 376 std::string tile_source; |
| 397 if (!initial_load_done_) { | 377 if (suggestion.providers_size()) { |
|
Alexei Svitkine (slow)
2015/08/25 15:01:19
Nit: != 0
Marc Treib
2015/08/25 15:19:32
Done.
| |
| 398 if (suggestion.providers_size()) { | 378 tile_source = |
| 399 std::string histogram = base::StringPrintf( | 379 base::StringPrintf(kHistogramServerFormat, suggestion.providers(0)); |
| 400 kImpressionServerHistogramFormat, suggestion.providers(0)); | 380 } else { |
| 401 LogHistogramEvent(histogram, i, num_sites_); | 381 tile_source = kHistogramServerName; |
| 402 } else { | |
| 403 UMA_HISTOGRAM_SPARSE_SLOWLY(kImpressionServerHistogramName, i); | |
| 404 } | |
| 405 } | 382 } |
| 383 tile_sources_.push_back(tile_source); | |
| 406 } | 384 } |
| 385 | |
| 386 received_most_visited_sites_ = true; | |
| 407 mv_source_ = SUGGESTIONS_SERVICE; | 387 mv_source_ = SUGGESTIONS_SERVICE; |
| 408 // Keep a copy of the suggestions for eventual logging. | |
| 409 server_suggestions_ = suggestions_profile; | |
| 410 AddPopularSites(&titles, &urls); | 388 AddPopularSites(&titles, &urls); |
| 411 NotifyMostVisitedURLsObserver(titles, urls); | 389 NotifyMostVisitedURLsObserver(titles, urls); |
| 412 } | 390 } |
| 413 | 391 |
| 414 void MostVisitedSites::AddPopularSites(std::vector<base::string16>* titles, | 392 void MostVisitedSites::AddPopularSites(std::vector<base::string16>* titles, |
| 415 std::vector<std::string>* urls) const { | 393 std::vector<std::string>* urls) { |
| 416 if (!popular_sites_) | 394 if (!popular_sites_) |
| 417 return; | 395 return; |
| 418 | 396 |
| 419 DCHECK_EQ(titles->size(), urls->size()); | 397 DCHECK_EQ(titles->size(), urls->size()); |
| 398 DCHECK_EQ(titles->size(), tile_sources_.size()); | |
| 420 DCHECK_LE(static_cast<int>(titles->size()), num_sites_); | 399 DCHECK_LE(static_cast<int>(titles->size()), num_sites_); |
| 421 | 400 |
| 422 // Collect all non-blacklisted popular suggestions. | 401 // Collect all non-blacklisted popular suggestions. |
| 423 std::vector<base::string16> new_titles; | 402 std::vector<base::string16> popular_titles; |
| 424 std::vector<std::string> new_urls; | 403 std::vector<std::string> popular_urls; |
| 425 scoped_refptr<TopSites> top_sites(TopSitesFactory::GetForProfile(profile_)); | 404 scoped_refptr<TopSites> top_sites(TopSitesFactory::GetForProfile(profile_)); |
| 426 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { | 405 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { |
| 427 // Skip blacklisted sites. | 406 // Skip blacklisted sites. |
| 428 if (top_sites && top_sites->IsBlacklisted(popular_site.url)) | 407 if (top_sites && top_sites->IsBlacklisted(popular_site.url)) |
| 429 continue; | 408 continue; |
| 430 | 409 |
| 431 new_titles.push_back(popular_site.title); | 410 popular_titles.push_back(popular_site.title); |
| 432 new_urls.push_back(popular_site.url.spec()); | 411 popular_urls.push_back(popular_site.url.spec()); |
| 433 if (static_cast<int>(new_titles.size()) >= num_sites_) | 412 if (static_cast<int>(popular_titles.size()) >= num_sites_) |
| 434 break; | 413 break; |
| 435 } | 414 } |
| 436 | 415 |
| 437 AddPopularSitesImpl(num_sites_, titles, urls, new_titles, new_urls); | 416 AddPopularSitesImpl( |
| 417 num_sites_, titles, urls, &tile_sources_, popular_titles, popular_urls); | |
| 438 } | 418 } |
| 439 | 419 |
| 440 // static | 420 // static |
| 441 void MostVisitedSites::AddPopularSitesImpl( | 421 void MostVisitedSites::AddPopularSitesImpl( |
| 442 int num_sites, | 422 int num_sites, |
| 443 std::vector<base::string16>* titles, | 423 std::vector<base::string16>* titles, |
| 444 std::vector<std::string>* urls, | 424 std::vector<std::string>* urls, |
| 425 std::vector<std::string>* tile_sources, | |
| 445 const std::vector<base::string16>& popular_titles, | 426 const std::vector<base::string16>& popular_titles, |
| 446 const std::vector<std::string>& popular_urls) { | 427 const std::vector<std::string>& popular_urls) { |
| 447 // Start off with the popular suggestions. | 428 // Start off with the popular suggestions. |
| 448 std::vector<base::string16> new_titles(popular_titles); | 429 std::vector<base::string16> new_titles(popular_titles); |
| 449 std::vector<std::string> new_urls(popular_urls); | 430 std::vector<std::string> new_urls(popular_urls); |
| 431 std::vector<std::string> new_tile_sources(new_titles.size(), | |
| 432 kHistogramPopularName); | |
| 450 | 433 |
| 451 // Now, go over the personalized suggestions and replace matching popular | 434 // Now, go over the personalized suggestions and replace matching popular |
| 452 // suggestions. This is so that when some of the popular suggestions become | 435 // suggestions. This is so that when some of the popular suggestions become |
| 453 // personal, they retain their absolute positions. | 436 // personal, they retain their absolute positions. |
| 454 std::vector<bool> new_is_personalized(new_titles.size(), false); | |
| 455 std::vector<base::string16> titles_to_insert; | 437 std::vector<base::string16> titles_to_insert; |
| 456 std::vector<std::string> urls_to_insert; | 438 std::vector<std::string> urls_to_insert; |
| 439 std::vector<std::string> tile_sources_to_insert; | |
| 457 for (size_t site_index = 0; site_index < titles->size(); site_index++) { | 440 for (size_t site_index = 0; site_index < titles->size(); site_index++) { |
| 458 const base::string16& title = (*titles)[site_index]; | 441 const base::string16& title = (*titles)[site_index]; |
| 459 const std::string& url = (*urls)[site_index]; | 442 const std::string& url = (*urls)[site_index]; |
| 443 const std::string& tile_source = (*tile_sources)[site_index]; | |
| 460 // See if we already have a matching popular site. | 444 // See if we already have a matching popular site. |
| 461 bool found = false; | 445 bool found = false; |
| 462 for (size_t i = 0; i < new_urls.size(); i++) { | 446 for (size_t i = 0; i < new_urls.size(); i++) { |
| 463 if (!new_is_personalized[i] && | 447 if (new_tile_sources[i] == kHistogramPopularName && |
| 464 GURL(new_urls[i]).host() == GURL(url).host()) { | 448 GURL(new_urls[i]).host() == GURL(url).host()) { |
| 465 // We have a matching popular sites suggestion. Replace it with the | 449 // We have a matching popular sites suggestion. Replace it with the |
| 466 // actual URL and title. | 450 // actual URL and title. |
| 467 new_titles[i] = title; | 451 new_titles[i] = title; |
| 468 new_urls[i] = url; | 452 new_urls[i] = url; |
| 469 new_is_personalized[i] = true; | 453 new_tile_sources[i] = tile_source; |
| 470 found = true; | 454 found = true; |
| 471 break; | 455 break; |
| 472 } | 456 } |
| 473 } | 457 } |
| 474 if (!found) { | 458 if (!found) { |
| 475 titles_to_insert.push_back(title); | 459 titles_to_insert.push_back(title); |
| 476 urls_to_insert.push_back(url); | 460 urls_to_insert.push_back(url); |
| 461 tile_sources_to_insert.push_back(tile_source); | |
| 477 } | 462 } |
| 478 } | 463 } |
| 479 | 464 |
| 480 // Append personalized suggestions at the end if there's room. | 465 // Append personalized suggestions at the end if there's room. |
| 481 size_t num_to_append = | 466 size_t num_to_append = |
| 482 std::min(static_cast<size_t>(num_sites) - new_titles.size(), | 467 std::min(static_cast<size_t>(num_sites) - new_titles.size(), |
| 483 titles_to_insert.size()); | 468 titles_to_insert.size()); |
| 484 new_titles.insert(new_titles.end(), | 469 new_titles.insert(new_titles.end(), |
| 485 titles_to_insert.end() - num_to_append, | 470 titles_to_insert.end() - num_to_append, |
| 486 titles_to_insert.end()); | 471 titles_to_insert.end()); |
| 487 new_urls.insert(new_urls.end(), | 472 new_urls.insert(new_urls.end(), |
| 488 urls_to_insert.end() - num_to_append, | 473 urls_to_insert.end() - num_to_append, |
| 489 urls_to_insert.end()); | 474 urls_to_insert.end()); |
| 490 new_is_personalized.insert(new_is_personalized.end(), num_to_append, true); | 475 new_tile_sources.insert(new_tile_sources.end(), |
| 476 tile_sources_to_insert.end() - num_to_append, | |
| 477 tile_sources_to_insert.end()); | |
| 491 | 478 |
| 492 // Finally, go over the remaining personalized suggestions and evict popular | 479 // Finally, go over the remaining personalized suggestions and evict popular |
| 493 // suggestions to accommodate them. Do it in reverse order, so the least | 480 // suggestions to accommodate them. Do it in reverse order, so the least |
| 494 // important popular suggestions will be evicted. | 481 // important popular suggestions will be evicted. |
| 495 for (size_t i = titles_to_insert.size() - num_to_append; i > 0; --i) { | 482 for (size_t i = titles_to_insert.size() - num_to_append; i > 0; --i) { |
| 496 const base::string16& title = titles_to_insert[i - 1]; | 483 const base::string16& title = titles_to_insert[i - 1]; |
| 497 const std::string& url = urls_to_insert[i - 1]; | 484 const std::string& url = urls_to_insert[i - 1]; |
| 485 const std::string& tile_source = tile_sources_to_insert[i - 1]; | |
| 498 for (size_t insert_i = new_titles.size(); insert_i > 0; --insert_i) { | 486 for (size_t insert_i = new_titles.size(); insert_i > 0; --insert_i) { |
| 499 size_t insert_index = insert_i - 1; | 487 size_t insert_index = insert_i - 1; |
| 500 if (!new_is_personalized[insert_index]) { | 488 if (new_tile_sources[insert_index] == kHistogramPopularName) { |
| 501 new_titles[insert_index] = title; | 489 new_titles[insert_index] = title; |
| 502 new_urls[insert_index] = url; | 490 new_urls[insert_index] = url; |
| 503 new_is_personalized[insert_index] = true; | 491 new_tile_sources[insert_index] = tile_source; |
| 504 break; | 492 break; |
| 505 } | 493 } |
| 506 } | 494 } |
| 507 } | 495 } |
| 508 | 496 |
| 509 titles->swap(new_titles); | 497 titles->swap(new_titles); |
| 510 urls->swap(new_urls); | 498 urls->swap(new_urls); |
| 499 tile_sources->swap(new_tile_sources); | |
| 511 } | 500 } |
| 512 | 501 |
| 513 void MostVisitedSites::NotifyMostVisitedURLsObserver( | 502 void MostVisitedSites::NotifyMostVisitedURLsObserver( |
| 514 const std::vector<base::string16>& titles, | 503 const std::vector<base::string16>& titles, |
| 515 const std::vector<std::string>& urls) { | 504 const std::vector<std::string>& urls) { |
| 516 DCHECK_EQ(titles.size(), urls.size()); | 505 DCHECK_EQ(titles.size(), urls.size()); |
| 517 if (!initial_load_done_) | 506 if (received_most_visited_sites_ && received_popular_sites_ && |
| 507 !recorded_uma_) { | |
| 508 RecordImpressionUMAMetrics(); | |
| 518 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumTilesHistogramName, titles.size()); | 509 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumTilesHistogramName, titles.size()); |
| 519 initial_load_done_ = true; | 510 recorded_uma_ = true; |
| 511 } | |
| 520 JNIEnv* env = AttachCurrentThread(); | 512 JNIEnv* env = AttachCurrentThread(); |
| 521 Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable( | 513 Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable( |
| 522 env, observer_.obj(), ToJavaArrayOfStrings(env, titles).obj(), | 514 env, observer_.obj(), ToJavaArrayOfStrings(env, titles).obj(), |
| 523 ToJavaArrayOfStrings(env, urls).obj()); | 515 ToJavaArrayOfStrings(env, urls).obj()); |
| 524 } | 516 } |
| 525 | 517 |
| 526 void MostVisitedSites::OnPopularSitesAvailable(bool success) { | 518 void MostVisitedSites::OnPopularSitesAvailable(bool success) { |
| 519 received_popular_sites_ = true; | |
| 520 | |
| 527 if (!success) { | 521 if (!success) { |
| 528 LOG(WARNING) << "Download of popular sites failed"; | 522 LOG(WARNING) << "Download of popular sites failed"; |
| 529 return; | 523 return; |
| 530 } | 524 } |
| 531 | 525 |
| 532 if (observer_.is_null()) | 526 if (observer_.is_null()) |
| 533 return; | 527 return; |
| 534 | 528 |
| 535 std::vector<std::string> urls; | 529 std::vector<std::string> urls; |
| 536 std::vector<std::string> favicon_urls; | 530 std::vector<std::string> favicon_urls; |
| 537 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { | 531 for (const PopularSites::Site& popular_site : popular_sites_->sites()) { |
| 538 urls.push_back(popular_site.url.spec()); | 532 urls.push_back(popular_site.url.spec()); |
| 539 favicon_urls.push_back(popular_site.favicon_url.spec()); | 533 favicon_urls.push_back(popular_site.favicon_url.spec()); |
| 540 } | 534 } |
| 541 JNIEnv* env = AttachCurrentThread(); | 535 JNIEnv* env = AttachCurrentThread(); |
| 542 Java_MostVisitedURLsObserver_onPopularURLsAvailable( | 536 Java_MostVisitedURLsObserver_onPopularURLsAvailable( |
| 543 env, observer_.obj(), ToJavaArrayOfStrings(env, urls).obj(), | 537 env, observer_.obj(), ToJavaArrayOfStrings(env, urls).obj(), |
| 544 ToJavaArrayOfStrings(env, favicon_urls).obj()); | 538 ToJavaArrayOfStrings(env, favicon_urls).obj()); |
| 545 | 539 |
| 546 QueryMostVisitedURLs(); | 540 QueryMostVisitedURLs(); |
| 547 } | 541 } |
| 548 | 542 |
| 549 void MostVisitedSites::RecordUMAMetrics() { | 543 void MostVisitedSites::RecordThumbnailUMAMetrics() { |
| 550 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumLocalThumbnailTilesHistogramName, | 544 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumLocalThumbnailTilesHistogramName, |
| 551 num_local_thumbs_); | 545 num_local_thumbs_); |
| 552 num_local_thumbs_ = 0; | 546 num_local_thumbs_ = 0; |
| 553 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumEmptyTilesHistogramName, num_empty_thumbs_); | 547 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumEmptyTilesHistogramName, num_empty_thumbs_); |
| 554 num_empty_thumbs_ = 0; | 548 num_empty_thumbs_ = 0; |
| 555 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumServerTilesHistogramName, num_server_thumbs_); | 549 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumServerTilesHistogramName, num_server_thumbs_); |
| 556 num_server_thumbs_ = 0; | 550 num_server_thumbs_ = 0; |
| 557 } | 551 } |
| 558 | 552 |
| 553 void MostVisitedSites::RecordImpressionUMAMetrics() { | |
| 554 for (size_t i = 0; i < tile_sources_.size(); i++) { | |
| 555 std::string histogram = base::StringPrintf(kImpressionHistogramFormat, | |
| 556 tile_sources_[i].c_str()); | |
| 557 LogHistogramEvent(histogram, static_cast<int>(i), num_sites_); | |
| 558 } | |
| 559 } | |
| 560 | |
| 559 void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) { | 561 void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) { |
| 560 } | 562 } |
| 561 | 563 |
| 562 void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites, | 564 void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites, |
| 563 ChangeReason change_reason) { | 565 ChangeReason change_reason) { |
| 564 if (mv_source_ == TOP_SITES) { | 566 if (mv_source_ == TOP_SITES) { |
| 565 // The displayed suggestions are invalidated. | 567 // The displayed suggestions are invalidated. |
| 566 QueryMostVisitedURLs(); | 568 QueryMostVisitedURLs(); |
| 567 } | 569 } |
| 568 } | 570 } |
| 569 | 571 |
| 570 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) { | 572 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) { |
| 571 MostVisitedSites* most_visited_sites = | 573 MostVisitedSites* most_visited_sites = |
| 572 new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile)); | 574 new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile)); |
| 573 return reinterpret_cast<intptr_t>(most_visited_sites); | 575 return reinterpret_cast<intptr_t>(most_visited_sites); |
| 574 } | 576 } |
| OLD | NEW |