Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / android / most_visited_sites.cc
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"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/history/history_types.h"
14 #include "chrome/browser/history/top_sites.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_android.h"
17 #include "chrome/browser/search/suggestions/proto/suggestions.pb.h"
18 #include "chrome/browser/search/suggestions/suggestions_service.h"
19 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
20 #include "chrome/browser/search/suggestions/suggestions_source.h"
21 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/url_data_source.h"
25 #include "jni/MostVisitedSites_jni.h"
26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "ui/gfx/android/java_bitmap.h"
28 #include "ui/gfx/codec/jpeg_codec.h"
29
30 using base::android::AttachCurrentThread;
31 using base::android::ConvertUTF8ToJavaString;
32 using base::android::ConvertJavaStringToUTF8;
33 using base::android::ScopedJavaGlobalRef;
34 using base::android::ToJavaArrayOfStrings;
35 using base::android::CheckException;
36 using content::BrowserThread;
37 using history::TopSites;
38 using suggestions::ChromeSuggestion;
39 using suggestions::SuggestionsProfile;
40 using suggestions::SuggestionsService;
41 using suggestions::SuggestionsServiceFactory;
42
43 namespace {
44
45 void ExtractMostVisitedTitlesAndURLs(
46     const history::MostVisitedURLList& visited_list,
47     std::vector<base::string16>* titles,
48     std::vector<std::string>* urls,
49     int num_sites) {
50   size_t max = static_cast<size_t>(num_sites);
51   for (size_t i = 0; i < visited_list.size() && i < max; ++i) {
52     const history::MostVisitedURL& visited = visited_list[i];
53
54     if (visited.url.is_empty())
55       break;  // This is the signal that there are no more real visited sites.
56
57     titles->push_back(visited.title);
58     urls->push_back(visited.url.spec());
59   }
60 }
61
62 void OnMostVisitedURLsAvailable(
63     ScopedJavaGlobalRef<jobject>* j_observer,
64     int num_sites,
65     const history::MostVisitedURLList& visited_list) {
66   std::vector<base::string16> titles;
67   std::vector<std::string> urls;
68   ExtractMostVisitedTitlesAndURLs(visited_list, &titles, &urls, num_sites);
69
70   JNIEnv* env = AttachCurrentThread();
71   Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable(
72       env,
73       j_observer->obj(),
74       ToJavaArrayOfStrings(env, titles).obj(),
75       ToJavaArrayOfStrings(env, urls).obj());
76 }
77
78 SkBitmap ExtractThumbnail(const base::RefCountedMemory& image_data) {
79   scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(
80       image_data.front(),
81       image_data.size()));
82   return image.get() ? *image : SkBitmap();
83 }
84
85 void OnObtainedThumbnail(
86     ScopedJavaGlobalRef<jobject>* bitmap,
87     ScopedJavaGlobalRef<jobject>* j_callback) {
88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89   JNIEnv* env = AttachCurrentThread();
90   Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable(
91       env, j_callback->obj(), bitmap->obj());
92 }
93
94 void GetUrlThumbnailTask(
95     std::string url_string,
96     scoped_refptr<TopSites> top_sites,
97     ScopedJavaGlobalRef<jobject>* j_callback) {
98   JNIEnv* env = AttachCurrentThread();
99
100   ScopedJavaGlobalRef<jobject>* j_bitmap_ref =
101       new ScopedJavaGlobalRef<jobject>();
102
103   GURL gurl(url_string);
104
105   scoped_refptr<base::RefCountedMemory> data;
106   if (top_sites->GetPageThumbnail(gurl, false, &data)) {
107     SkBitmap thumbnail_bitmap = ExtractThumbnail(*data.get());
108     if (!thumbnail_bitmap.empty()) {
109       j_bitmap_ref->Reset(
110           env,
111           gfx::ConvertToJavaBitmap(&thumbnail_bitmap).obj());
112     }
113   }
114
115   // Since j_callback is owned by this callback, when the callback falls out of
116   // scope it will be deleted. We need to pass ownership to the next callback.
117   ScopedJavaGlobalRef<jobject>* j_callback_pass =
118       new ScopedJavaGlobalRef<jobject>(*j_callback);
119   BrowserThread::PostTask(
120       BrowserThread::UI, FROM_HERE,
121       base::Bind(
122           &OnObtainedThumbnail,
123           base::Owned(j_bitmap_ref), base::Owned(j_callback_pass)));
124 }
125
126 }  // namespace
127
128 MostVisitedSites::MostVisitedSites(Profile* profile)
129     : profile_(profile), num_sites_(0), weak_ptr_factory_(this) {
130   // Register the debugging page for the Suggestions Service and the thumbnails
131   // debugging page.
132   content::URLDataSource::Add(profile_,
133                               new suggestions::SuggestionsSource(profile_));
134   content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
135 }
136
137 MostVisitedSites::~MostVisitedSites() {
138 }
139
140 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) {
141   delete this;
142 }
143
144 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env,
145                                                   jobject obj,
146                                                   jobject j_observer,
147                                                   jint num_sites) {
148   observer_.Reset(env, j_observer);
149   num_sites_ = num_sites;
150
151   QueryMostVisitedURLs();
152
153   history::TopSites* top_sites = profile_->GetTopSites();
154   if (top_sites) {
155     // TopSites updates itself after a delay. To ensure up-to-date results,
156     // force an update now.
157     top_sites->SyncWithHistory();
158
159     // Register for notification when TopSites changes so that we can update
160     // ourself.
161     registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
162                    content::Source<history::TopSites>(top_sites));
163   }
164 }
165
166 // May be called from any thread
167 void MostVisitedSites::GetURLThumbnail(JNIEnv* env,
168                                        jobject obj,
169                                        jstring url,
170                                        jobject j_callback_obj) {
171   ScopedJavaGlobalRef<jobject>* j_callback =
172       new ScopedJavaGlobalRef<jobject>();
173   j_callback->Reset(env, j_callback_obj);
174
175   std::string url_string = ConvertJavaStringToUTF8(env, url);
176   scoped_refptr<TopSites> top_sites(profile_->GetTopSites());
177   BrowserThread::PostTask(
178       BrowserThread::DB, FROM_HERE, base::Bind(
179           &GetUrlThumbnailTask,
180           url_string,
181           top_sites, base::Owned(j_callback)));
182 }
183
184 void MostVisitedSites::BlacklistUrl(JNIEnv* env,
185                                     jobject obj,
186                                     jstring j_url) {
187   TopSites* top_sites = profile_->GetTopSites();
188   if (!top_sites)
189     return;
190
191   std::string url_string = ConvertJavaStringToUTF8(env, j_url);
192   top_sites->AddBlacklistedURL(GURL(url_string));
193 }
194
195 void MostVisitedSites::Observe(int type,
196                                const content::NotificationSource& source,
197                                const content::NotificationDetails& details) {
198   DCHECK_EQ(type, chrome::NOTIFICATION_TOP_SITES_CHANGED);
199
200   // Most visited urls changed, query again.
201   QueryMostVisitedURLs();
202 }
203
204 // static
205 bool MostVisitedSites::Register(JNIEnv* env) {
206   return RegisterNativesImpl(env);
207 }
208
209 void MostVisitedSites::QueryMostVisitedURLs() {
210   SuggestionsServiceFactory* suggestions_service_factory =
211       SuggestionsServiceFactory::GetInstance();
212   SuggestionsService* suggestions_service =
213       suggestions_service_factory->GetForProfile(profile_);
214   if (suggestions_service) {
215     // Suggestions service is enabled, initiate a query.
216     suggestions_service->FetchSuggestionsData(
217         base::Bind(
218           &MostVisitedSites::OnSuggestionsProfileAvailable,
219           weak_ptr_factory_.GetWeakPtr(),
220           base::Owned(new ScopedJavaGlobalRef<jobject>(observer_))));
221   } else {
222     InitiateTopSitesQuery();
223   }
224 }
225
226 void MostVisitedSites::InitiateTopSitesQuery() {
227   TopSites* top_sites = profile_->GetTopSites();
228   if (!top_sites)
229     return;
230
231   top_sites->GetMostVisitedURLs(
232       base::Bind(
233           &OnMostVisitedURLsAvailable,
234           base::Owned(new ScopedJavaGlobalRef<jobject>(observer_)),
235           num_sites_),
236       false);
237 }
238
239 void MostVisitedSites::OnSuggestionsProfileAvailable(
240     ScopedJavaGlobalRef<jobject>* j_observer,
241     const SuggestionsProfile& suggestions_profile) {
242   size_t size = suggestions_profile.suggestions_size();
243   if (size == 0) {
244     // No suggestions data available, initiate Top Sites query.
245     InitiateTopSitesQuery();
246     return;
247   }
248
249   std::vector<base::string16> titles;
250   std::vector<std::string> urls;
251   for (size_t i = 0; i < size; ++i) {
252     const ChromeSuggestion& suggestion = suggestions_profile.suggestions(i);
253     titles.push_back(base::UTF8ToUTF16(suggestion.title()));
254     urls.push_back(suggestion.url());
255   }
256
257   JNIEnv* env = AttachCurrentThread();
258   Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable(
259       env,
260       j_observer->obj(),
261       ToJavaArrayOfStrings(env, titles).obj(),
262       ToJavaArrayOfStrings(env, urls).obj());
263 }
264
265 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) {
266   MostVisitedSites* most_visited_sites =
267       new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile));
268   return reinterpret_cast<intptr_t>(most_visited_sites);
269 }