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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 using content::BrowserThread; | 49 using content::BrowserThread; |
50 using history::TopSites; | 50 using history::TopSites; |
51 using suggestions::ChromeSuggestion; | 51 using suggestions::ChromeSuggestion; |
52 using suggestions::SuggestionsProfile; | 52 using suggestions::SuggestionsProfile; |
53 using suggestions::SuggestionsService; | 53 using suggestions::SuggestionsService; |
54 using suggestions::SuggestionsServiceFactory; | 54 using suggestions::SuggestionsServiceFactory; |
55 using suggestions::SyncState; | 55 using suggestions::SyncState; |
56 | 56 |
57 namespace { | 57 namespace { |
58 | 58 |
59 // Total number of tiles displayed. | |
60 const char kNumTilesHistogramName[] = "NewTabPage.NumberOfTiles"; | |
61 // Tracking thumbnails. | |
62 const char kNumLocalThumbnailTilesHistogramName[] = | |
63 "NewTabPage.NumberOfThumbnailTiles"; | |
64 const char kNumEmptyTilesHistogramName[] = "NewTabPage.NumberOfGrayTiles"; | |
65 const char kNumServerTilesHistogramName[] = "NewTabPage.NumberOfExternalTiles"; | |
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. | 59 // Identifiers for the various tile sources. |
72 const char kHistogramClientName[] = "client"; | 60 const char kHistogramClientName[] = "client"; |
73 const char kHistogramServerName[] = "server"; | 61 const char kHistogramServerName[] = "server"; |
74 const char kHistogramServerFormat[] = "server%d"; | 62 const char kHistogramServerFormat[] = "server%d"; |
75 const char kHistogramPopularName[] = "popular"; | 63 const char kHistogramPopularName[] = "popular"; |
76 | 64 |
77 const char kPopularSitesFieldTrialName[] = "NTPPopularSites"; | 65 const char kPopularSitesFieldTrialName[] = "NTPPopularSites"; |
78 | 66 |
| 67 // The visual type of a most visited tile. |
| 68 // |
| 69 // These values must stay in sync with the MostVisitedTileType enum |
| 70 // in histograms.xml. |
| 71 // |
| 72 // A Java counterpart will be generated for this enum. |
| 73 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp |
| 74 enum MostVisitedTileType { |
| 75 // The icon or thumbnail hasn't loaded yet. |
| 76 NONE, |
| 77 // The item displays a site's actual favicon or touch icon. |
| 78 ICON_REAL, |
| 79 // The item displays a color derived from the site's favicon or touch icon. |
| 80 ICON_COLOR, |
| 81 // The item displays a default gray box in place of an icon. |
| 82 ICON_DEFAULT, |
| 83 // The item displays a locally-captured thumbnail of the site content. |
| 84 THUMBNAIL_LOCAL, |
| 85 // The item displays a server-provided thumbnail of the site content. |
| 86 THUMBNAIL_SERVER, |
| 87 // The item displays a default graphic in place of a thumbnail. |
| 88 THUMBNAIL_DEFAULT, |
| 89 NUM_TILE_TYPES, |
| 90 }; |
| 91 |
79 scoped_ptr<SkBitmap> MaybeFetchLocalThumbnail( | 92 scoped_ptr<SkBitmap> MaybeFetchLocalThumbnail( |
80 const GURL& url, | 93 const GURL& url, |
81 const scoped_refptr<TopSites>& top_sites) { | 94 const scoped_refptr<TopSites>& top_sites) { |
82 DCHECK_CURRENTLY_ON(BrowserThread::DB); | 95 DCHECK_CURRENTLY_ON(BrowserThread::DB); |
83 scoped_refptr<base::RefCountedMemory> image; | 96 scoped_refptr<base::RefCountedMemory> image; |
84 scoped_ptr<SkBitmap> bitmap; | 97 scoped_ptr<SkBitmap> bitmap; |
85 if (top_sites && top_sites->GetPageThumbnail(url, false, &image)) | 98 if (top_sites && top_sites->GetPageThumbnail(url, false, &image)) |
86 bitmap.reset(gfx::JPEGCodec::Decode(image->front(), image->size())); | 99 bitmap.reset(gfx::JPEGCodec::Decode(image->front(), image->size())); |
87 return bitmap.Pass(); | 100 return bitmap.Pass(); |
88 } | 101 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 ? base::StringPrintf(kHistogramServerFormat, provider_index) | 212 ? base::StringPrintf(kHistogramServerFormat, provider_index) |
200 : kHistogramServerName; | 213 : kHistogramServerName; |
201 } | 214 } |
202 NOTREACHED(); | 215 NOTREACHED(); |
203 return std::string(); | 216 return std::string(); |
204 } | 217 } |
205 | 218 |
206 MostVisitedSites::MostVisitedSites(Profile* profile) | 219 MostVisitedSites::MostVisitedSites(Profile* profile) |
207 : profile_(profile), num_sites_(0), received_most_visited_sites_(false), | 220 : profile_(profile), num_sites_(0), received_most_visited_sites_(false), |
208 received_popular_sites_(false), recorded_uma_(false), | 221 received_popular_sites_(false), recorded_uma_(false), |
209 num_local_thumbs_(0), num_server_thumbs_(0), num_empty_thumbs_(0), | |
210 scoped_observer_(this), weak_ptr_factory_(this) { | 222 scoped_observer_(this), weak_ptr_factory_(this) { |
211 // Register the debugging page for the Suggestions Service and the thumbnails | 223 // Register the debugging page for the Suggestions Service and the thumbnails |
212 // debugging page. | 224 // debugging page. |
213 content::URLDataSource::Add(profile_, | 225 content::URLDataSource::Add(profile_, |
214 new suggestions::SuggestionsSource(profile_)); | 226 new suggestions::SuggestionsSource(profile_)); |
215 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_)); | 227 content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_)); |
216 | 228 |
217 // Register this class as an observer to the sync service. It is important to | 229 // Register this class as an observer to the sync service. It is important to |
218 // be notified of changes in the sync state such as initialization, sync | 230 // be notified of changes in the sync state such as initialization, sync |
219 // being enabled or disabled, etc. | 231 // being enabled or disabled, etc. |
220 ProfileSyncService* profile_sync_service = | 232 ProfileSyncService* profile_sync_service = |
221 ProfileSyncServiceFactory::GetForProfile(profile_); | 233 ProfileSyncServiceFactory::GetForProfile(profile_); |
222 if (profile_sync_service) | 234 if (profile_sync_service) |
223 profile_sync_service->AddObserver(this); | 235 profile_sync_service->AddObserver(this); |
224 } | 236 } |
225 | 237 |
226 MostVisitedSites::~MostVisitedSites() { | 238 MostVisitedSites::~MostVisitedSites() { |
227 ProfileSyncService* profile_sync_service = | 239 ProfileSyncService* profile_sync_service = |
228 ProfileSyncServiceFactory::GetForProfile(profile_); | 240 ProfileSyncServiceFactory::GetForProfile(profile_); |
229 if (profile_sync_service && profile_sync_service->HasObserver(this)) | 241 if (profile_sync_service && profile_sync_service->HasObserver(this)) |
230 profile_sync_service->RemoveObserver(this); | 242 profile_sync_service->RemoveObserver(this); |
231 } | 243 } |
232 | 244 |
233 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) { | 245 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) { |
234 delete this; | 246 delete this; |
235 } | 247 } |
236 | 248 |
237 void MostVisitedSites::OnLoadingComplete(JNIEnv* env, jobject obj) { | |
238 RecordThumbnailUMAMetrics(); | |
239 } | |
240 | |
241 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env, | 249 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env, |
242 jobject obj, | 250 jobject obj, |
243 jobject j_observer, | 251 jobject j_observer, |
244 jint num_sites) { | 252 jint num_sites) { |
245 observer_.Reset(env, j_observer); | 253 observer_.Reset(env, j_observer); |
246 num_sites_ = num_sites; | 254 num_sites_ = num_sites; |
247 | 255 |
248 if (ShouldShowPopularSites() && | 256 if (ShouldShowPopularSites() && |
249 NeedPopularSites(profile_->GetPrefs(), num_sites_)) { | 257 NeedPopularSites(profile_->GetPrefs(), num_sites_)) { |
250 popular_sites_.reset(new PopularSites( | 258 popular_sites_.reset(new PopularSites( |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 } | 344 } |
337 | 345 |
338 void MostVisitedSites::OnObtainedThumbnail( | 346 void MostVisitedSites::OnObtainedThumbnail( |
339 bool is_local_thumbnail, | 347 bool is_local_thumbnail, |
340 scoped_ptr<ScopedJavaGlobalRef<jobject>> j_callback, | 348 scoped_ptr<ScopedJavaGlobalRef<jobject>> j_callback, |
341 const GURL& url, | 349 const GURL& url, |
342 const SkBitmap* bitmap) { | 350 const SkBitmap* bitmap) { |
343 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 351 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
344 JNIEnv* env = AttachCurrentThread(); | 352 JNIEnv* env = AttachCurrentThread(); |
345 ScopedJavaLocalRef<jobject> j_bitmap; | 353 ScopedJavaLocalRef<jobject> j_bitmap; |
346 if (bitmap) { | 354 if (bitmap) |
347 j_bitmap = gfx::ConvertToJavaBitmap(bitmap); | 355 j_bitmap = gfx::ConvertToJavaBitmap(bitmap); |
348 if (is_local_thumbnail) { | |
349 ++num_local_thumbs_; | |
350 } else { | |
351 ++num_server_thumbs_; | |
352 } | |
353 } else { | |
354 ++num_empty_thumbs_; | |
355 } | |
356 Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable( | 356 Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable( |
357 env, j_callback->obj(), j_bitmap.obj()); | 357 env, j_callback->obj(), j_bitmap.obj(), is_local_thumbnail); |
358 } | 358 } |
359 | 359 |
360 void MostVisitedSites::BlacklistUrl(JNIEnv* env, | 360 void MostVisitedSites::BlacklistUrl(JNIEnv* env, |
361 jobject obj, | 361 jobject obj, |
362 jstring j_url) { | 362 jstring j_url) { |
363 GURL url(ConvertJavaStringToUTF8(env, j_url)); | 363 GURL url(ConvertJavaStringToUTF8(env, j_url)); |
364 | 364 |
365 // Always blacklist in the local TopSites. | 365 // Always blacklist in the local TopSites. |
366 scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_); | 366 scoped_refptr<TopSites> top_sites = TopSitesFactory::GetForProfile(profile_); |
367 if (top_sites) | 367 if (top_sites) |
368 top_sites->AddBlacklistedURL(url); | 368 top_sites->AddBlacklistedURL(url); |
369 | 369 |
370 // Only blacklist in the server-side suggestions service if it's active. | 370 // Only blacklist in the server-side suggestions service if it's active. |
371 if (mv_source_ == SUGGESTIONS_SERVICE) { | 371 if (mv_source_ == SUGGESTIONS_SERVICE) { |
372 SuggestionsService* suggestions_service = | 372 SuggestionsService* suggestions_service = |
373 SuggestionsServiceFactory::GetForProfile(profile_); | 373 SuggestionsServiceFactory::GetForProfile(profile_); |
374 DCHECK(suggestions_service); | 374 DCHECK(suggestions_service); |
375 suggestions_service->BlacklistURL( | 375 suggestions_service->BlacklistURL( |
376 url, base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, | 376 url, base::Bind(&MostVisitedSites::OnSuggestionsProfileAvailable, |
377 weak_ptr_factory_.GetWeakPtr()), | 377 weak_ptr_factory_.GetWeakPtr()), |
378 base::Closure()); | 378 base::Closure()); |
379 } | 379 } |
380 } | 380 } |
381 | 381 |
| 382 void MostVisitedSites::RecordTileTypeMetrics(JNIEnv* env, |
| 383 jobject obj, |
| 384 jintArray jtile_types, |
| 385 jboolean is_icon_mode) { |
| 386 std::vector<int> tile_types; |
| 387 base::android::JavaIntArrayToIntVector(env, jtile_types, &tile_types); |
| 388 DCHECK_EQ(current_suggestions_.size(), tile_types.size()); |
| 389 |
| 390 int counts_per_type[NUM_TILE_TYPES] = {0}; |
| 391 for (size_t i = 0; i < tile_types.size(); ++i) { |
| 392 int tile_type = tile_types[i]; |
| 393 ++counts_per_type[tile_type]; |
| 394 std::string histogram = base::StringPrintf( |
| 395 "NewTabPage.TileType.%s", |
| 396 current_suggestions_[i]->GetSourceHistogramName().c_str()); |
| 397 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES); |
| 398 } |
| 399 |
| 400 if (is_icon_mode) { |
| 401 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsReal", |
| 402 counts_per_type[ICON_REAL]); |
| 403 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsColor", |
| 404 counts_per_type[ICON_COLOR]); |
| 405 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.IconsGray", |
| 406 counts_per_type[ICON_DEFAULT]); |
| 407 } else { |
| 408 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfThumbnailTiles", |
| 409 counts_per_type[THUMBNAIL_LOCAL]); |
| 410 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfExternalTiles", |
| 411 counts_per_type[THUMBNAIL_SERVER]); |
| 412 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfGrayTiles", |
| 413 counts_per_type[THUMBNAIL_DEFAULT]); |
| 414 } |
| 415 } |
| 416 |
382 void MostVisitedSites::RecordOpenedMostVisitedItem(JNIEnv* env, | 417 void MostVisitedSites::RecordOpenedMostVisitedItem(JNIEnv* env, |
383 jobject obj, | 418 jobject obj, |
384 jint index) { | 419 jint index, |
| 420 jint tile_type) { |
385 DCHECK_GE(index, 0); | 421 DCHECK_GE(index, 0); |
386 DCHECK_LT(index, static_cast<int>(current_suggestions_.size())); | 422 DCHECK_LT(index, static_cast<int>(current_suggestions_.size())); |
387 std::string histogram = base::StringPrintf( | 423 std::string histogram = base::StringPrintf( |
388 kOpenedItemHistogramFormat, | 424 "NewTabPage.MostVisited.%s", |
389 current_suggestions_[index]->GetSourceHistogramName().c_str()); | 425 current_suggestions_[index]->GetSourceHistogramName().c_str()); |
390 LogHistogramEvent(histogram, index, num_sites_); | 426 LogHistogramEvent(histogram, index, num_sites_); |
| 427 |
| 428 histogram = base::StringPrintf( |
| 429 "NewTabPage.TileTypeClicked.%s", |
| 430 current_suggestions_[index]->GetSourceHistogramName().c_str()); |
| 431 LogHistogramEvent(histogram, tile_type, NUM_TILE_TYPES); |
391 } | 432 } |
392 | 433 |
393 void MostVisitedSites::OnStateChanged() { | 434 void MostVisitedSites::OnStateChanged() { |
394 // There have been changes to the sync state. This class cares about a few | 435 // There have been changes to the sync state. This class cares about a few |
395 // (just initialized, enabled/disabled or history sync state changed). Re-run | 436 // (just initialized, enabled/disabled or history sync state changed). Re-run |
396 // the query code which will use the proper state. | 437 // the query code which will use the proper state. |
397 QueryMostVisitedURLs(); | 438 QueryMostVisitedURLs(); |
398 } | 439 } |
399 | 440 |
400 // static | 441 // static |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 // Return destination postions filled so far which becomes the start_position | 701 // Return destination postions filled so far which becomes the start_position |
661 // for future runs. | 702 // for future runs. |
662 return i; | 703 return i; |
663 } | 704 } |
664 | 705 |
665 void MostVisitedSites::NotifyMostVisitedURLsObserver() { | 706 void MostVisitedSites::NotifyMostVisitedURLsObserver() { |
666 size_t num_suggestions = current_suggestions_.size(); | 707 size_t num_suggestions = current_suggestions_.size(); |
667 if (received_most_visited_sites_ && received_popular_sites_ && | 708 if (received_most_visited_sites_ && received_popular_sites_ && |
668 !recorded_uma_) { | 709 !recorded_uma_) { |
669 RecordImpressionUMAMetrics(); | 710 RecordImpressionUMAMetrics(); |
670 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumTilesHistogramName, num_suggestions); | 711 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", num_suggestions); |
671 recorded_uma_ = true; | 712 recorded_uma_ = true; |
672 } | 713 } |
673 std::vector<base::string16> titles; | 714 std::vector<base::string16> titles; |
674 std::vector<std::string> urls; | 715 std::vector<std::string> urls; |
675 titles.reserve(num_suggestions); | 716 titles.reserve(num_suggestions); |
676 urls.reserve(num_suggestions); | 717 urls.reserve(num_suggestions); |
677 for (const Suggestion* suggestion : current_suggestions_) { | 718 for (const Suggestion* suggestion : current_suggestions_) { |
678 titles.push_back(suggestion->title); | 719 titles.push_back(suggestion->title); |
679 urls.push_back(suggestion->url.spec()); | 720 urls.push_back(suggestion->url.spec()); |
680 } | 721 } |
(...skipping 22 matching lines...) Expand all Loading... |
703 favicon_urls.push_back(popular_site.favicon_url.spec()); | 744 favicon_urls.push_back(popular_site.favicon_url.spec()); |
704 } | 745 } |
705 JNIEnv* env = AttachCurrentThread(); | 746 JNIEnv* env = AttachCurrentThread(); |
706 Java_MostVisitedURLsObserver_onPopularURLsAvailable( | 747 Java_MostVisitedURLsObserver_onPopularURLsAvailable( |
707 env, observer_.obj(), ToJavaArrayOfStrings(env, urls).obj(), | 748 env, observer_.obj(), ToJavaArrayOfStrings(env, urls).obj(), |
708 ToJavaArrayOfStrings(env, favicon_urls).obj()); | 749 ToJavaArrayOfStrings(env, favicon_urls).obj()); |
709 | 750 |
710 QueryMostVisitedURLs(); | 751 QueryMostVisitedURLs(); |
711 } | 752 } |
712 | 753 |
713 void MostVisitedSites::RecordThumbnailUMAMetrics() { | |
714 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumLocalThumbnailTilesHistogramName, | |
715 num_local_thumbs_); | |
716 num_local_thumbs_ = 0; | |
717 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumEmptyTilesHistogramName, num_empty_thumbs_); | |
718 num_empty_thumbs_ = 0; | |
719 UMA_HISTOGRAM_SPARSE_SLOWLY(kNumServerTilesHistogramName, num_server_thumbs_); | |
720 num_server_thumbs_ = 0; | |
721 } | |
722 | |
723 void MostVisitedSites::RecordImpressionUMAMetrics() { | 754 void MostVisitedSites::RecordImpressionUMAMetrics() { |
724 for (size_t i = 0; i < current_suggestions_.size(); i++) { | 755 for (size_t i = 0; i < current_suggestions_.size(); i++) { |
725 std::string histogram = base::StringPrintf( | 756 std::string histogram = base::StringPrintf( |
726 kImpressionHistogramFormat, | 757 "NewTabPage.SuggestionsImpression.%s", |
727 current_suggestions_[i]->GetSourceHistogramName().c_str()); | 758 current_suggestions_[i]->GetSourceHistogramName().c_str()); |
728 LogHistogramEvent(histogram, static_cast<int>(i), num_sites_); | 759 LogHistogramEvent(histogram, static_cast<int>(i), num_sites_); |
729 } | 760 } |
730 } | 761 } |
731 | 762 |
732 void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) { | 763 void MostVisitedSites::TopSitesLoaded(history::TopSites* top_sites) { |
733 } | 764 } |
734 | 765 |
735 void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites, | 766 void MostVisitedSites::TopSitesChanged(history::TopSites* top_sites, |
736 ChangeReason change_reason) { | 767 ChangeReason change_reason) { |
737 if (mv_source_ == TOP_SITES) { | 768 if (mv_source_ == TOP_SITES) { |
738 // The displayed suggestions are invalidated. | 769 // The displayed suggestions are invalidated. |
739 QueryMostVisitedURLs(); | 770 InitiateTopSitesQuery(); |
740 } | 771 } |
741 } | 772 } |
742 | 773 |
743 static jlong Init(JNIEnv* env, | 774 static jlong Init(JNIEnv* env, |
744 const JavaParamRef<jobject>& obj, | 775 const JavaParamRef<jobject>& obj, |
745 const JavaParamRef<jobject>& jprofile) { | 776 const JavaParamRef<jobject>& jprofile) { |
746 MostVisitedSites* most_visited_sites = | 777 MostVisitedSites* most_visited_sites = |
747 new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile)); | 778 new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile)); |
748 return reinterpret_cast<intptr_t>(most_visited_sites); | 779 return reinterpret_cast<intptr_t>(most_visited_sites); |
749 } | 780 } |
OLD | NEW |