ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / android / favicon_helper.cc
blob7f008f274cc3b959aac130cdbce5c67125101725
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/android/favicon_helper.h"
7 #include <jni.h>
9 #include <vector>
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_array.h"
13 #include "base/android/jni_string.h"
14 #include "base/android/scoped_java_ref.h"
15 #include "base/bind.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/browser/favicon/favicon_service_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_android.h"
21 #include "chrome/browser/sync/profile_sync_service.h"
22 #include "chrome/browser/sync/profile_sync_service_factory.h"
23 #include "components/favicon/core/favicon_service.h"
24 #include "components/favicon_base/favicon_util.h"
25 #include "components/favicon_base/select_favicon_frames.h"
26 #include "components/sync_driver/open_tabs_ui_delegate.h"
27 #include "content/public/browser/web_contents.h"
28 #include "jni/FaviconHelper_jni.h"
29 #include "third_party/skia/include/core/SkBitmap.h"
30 #include "ui/gfx/android/java_bitmap.h"
31 #include "ui/gfx/codec/png_codec.h"
32 #include "ui/gfx/color_analysis.h"
33 #include "ui/gfx/color_utils.h"
34 #include "ui/gfx/favicon_size.h"
35 #include "ui/gfx/image/image_skia.h"
37 using base::android::ScopedJavaGlobalRef;
38 using base::android::ScopedJavaLocalRef;
39 using base::android::AttachCurrentThread;
40 using base::android::ConvertJavaStringToUTF16;
41 using base::android::ConvertJavaStringToUTF8;
42 using base::android::ConvertUTF8ToJavaString;
44 namespace {
46 void OnLocalFaviconAvailable(
47 ScopedJavaGlobalRef<jobject>* j_favicon_image_callback,
48 const favicon_base::FaviconRawBitmapResult& result) {
49 JNIEnv* env = AttachCurrentThread();
51 // Convert favicon_image_result to java objects.
52 ScopedJavaLocalRef<jstring> j_icon_url =
53 ConvertUTF8ToJavaString(env, result.icon_url.spec());
54 ScopedJavaLocalRef<jobject> j_favicon_bitmap;
55 if (result.is_valid()) {
56 SkBitmap favicon_bitmap;
57 gfx::PNGCodec::Decode(result.bitmap_data->front(),
58 result.bitmap_data->size(),
59 &favicon_bitmap);
60 if (!favicon_bitmap.isNull())
61 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
64 // Call java side OnLocalFaviconAvailable method.
65 Java_FaviconImageCallback_onFaviconAvailable(env,
66 j_favicon_image_callback->obj(),
67 j_favicon_bitmap.obj(),
68 j_icon_url.obj());
71 void OnFaviconRawBitmapResultAvailable(
72 ScopedJavaGlobalRef<jobject>* j_favicon_image_callback,
73 const favicon_base::FaviconRawBitmapResult& favicon_bitmap_result) {
74 JNIEnv* env = AttachCurrentThread();
76 // Convert favicon_image_result to java objects.
77 ScopedJavaLocalRef<jstring> j_icon_url =
78 ConvertUTF8ToJavaString(env, favicon_bitmap_result.icon_url.spec());
80 SkBitmap favicon_bitmap;
81 if (favicon_bitmap_result.is_valid()) {
82 gfx::PNGCodec::Decode(favicon_bitmap_result.bitmap_data->front(),
83 favicon_bitmap_result.bitmap_data->size(),
84 &favicon_bitmap);
86 ScopedJavaLocalRef<jobject> j_favicon_bitmap;
87 if (!favicon_bitmap.isNull())
88 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
90 // Call java side OnLocalFaviconAvailable method.
91 Java_FaviconImageCallback_onFaviconAvailable(env,
92 j_favicon_image_callback->obj(),
93 j_favicon_bitmap.obj(),
94 j_icon_url.obj());
97 void OnFaviconDownloaded(
98 const ScopedJavaGlobalRef<jobject>& j_availability_callback,
99 Profile* profile,
100 const GURL& page_url,
101 int download_request_id,
102 int http_status_code,
103 const GURL& image_url,
104 const std::vector<SkBitmap>& bitmaps,
105 const std::vector<gfx::Size>& original_sizes) {
106 bool success = !bitmaps.empty();
107 if (success) {
108 gfx::Image image = gfx::Image(CreateFaviconImageSkia(bitmaps,
109 original_sizes,
110 gfx::kFaviconSize,
111 nullptr));
112 favicon_base::SetFaviconColorSpace(&image);
113 favicon::FaviconService* service = FaviconServiceFactory::GetForProfile(
114 profile, ServiceAccessType::IMPLICIT_ACCESS);
115 service->SetFavicons(page_url, image_url, favicon_base::FAVICON, image);
118 JNIEnv* env = AttachCurrentThread();
119 Java_FaviconAvailabilityCallback_onFaviconAvailabilityChecked(
120 env, j_availability_callback.obj(), success);
123 void OnFaviconImageResultAvailable(
124 const ScopedJavaGlobalRef<jobject>& j_availability_callback,
125 Profile* profile,
126 content::WebContents* web_contents,
127 const GURL& page_url,
128 const GURL& favicon_url,
129 const favicon_base::FaviconImageResult& result) {
130 // If there already is a favicon, return immediately.
131 if (!result.image.IsEmpty()) {
132 JNIEnv* env = AttachCurrentThread();
133 Java_FaviconAvailabilityCallback_onFaviconAvailabilityChecked(
134 env, j_availability_callback.obj(), false);
135 return;
138 web_contents->DownloadImage(favicon_url, true, 0, false,
139 base::Bind(OnFaviconDownloaded,
140 j_availability_callback,
141 profile, page_url));
144 } // namespace
146 static jlong Init(JNIEnv* env, jclass clazz) {
147 return reinterpret_cast<intptr_t>(new FaviconHelper());
150 FaviconHelper::FaviconHelper() {
151 cancelable_task_tracker_.reset(new base::CancelableTaskTracker());
154 void FaviconHelper::Destroy(JNIEnv* env, jobject obj) {
155 delete this;
158 jboolean FaviconHelper::GetLocalFaviconImageForURL(
159 JNIEnv* env,
160 jobject obj,
161 jobject j_profile,
162 jstring j_page_url,
163 jint j_icon_types,
164 jint j_desired_size_in_pixel,
165 jobject j_favicon_image_callback) {
166 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
167 DCHECK(profile);
168 if (!profile)
169 return false;
171 favicon::FaviconService* favicon_service =
172 FaviconServiceFactory::GetForProfile(profile,
173 ServiceAccessType::EXPLICIT_ACCESS);
174 DCHECK(favicon_service);
175 if (!favicon_service)
176 return false;
178 ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback =
179 new ScopedJavaGlobalRef<jobject>();
180 j_scoped_favicon_callback->Reset(env, j_favicon_image_callback);
182 favicon_base::FaviconRawBitmapCallback callback_runner = base::Bind(
183 &OnLocalFaviconAvailable, base::Owned(j_scoped_favicon_callback));
185 favicon_service->GetRawFaviconForPageURL(
186 GURL(ConvertJavaStringToUTF16(env, j_page_url)),
187 static_cast<int>(j_icon_types),
188 static_cast<int>(j_desired_size_in_pixel),
189 callback_runner,
190 cancelable_task_tracker_.get());
192 return true;
195 void FaviconHelper::GetLargestRawFaviconForUrl(
196 JNIEnv* env,
197 jobject obj,
198 jobject j_profile,
199 jstring j_page_url,
200 jintArray j_icon_types,
201 jint j_min_size_threshold_px,
202 jobject j_favicon_image_callback) {
203 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
204 DCHECK(profile);
205 if (!profile)
206 return;
208 favicon::FaviconService* favicon_service =
209 FaviconServiceFactory::GetForProfile(profile,
210 ServiceAccessType::EXPLICIT_ACCESS);
211 DCHECK(favicon_service);
212 if (!favicon_service)
213 return;
215 std::vector<int> icon_types;
216 base::android::JavaIntArrayToIntVector(env, j_icon_types, &icon_types);
218 ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback =
219 new ScopedJavaGlobalRef<jobject>();
220 j_scoped_favicon_callback->Reset(env, j_favicon_image_callback);
222 favicon_base::FaviconRawBitmapCallback callback_runner =
223 base::Bind(&OnFaviconRawBitmapResultAvailable,
224 base::Owned(j_scoped_favicon_callback));
225 favicon_service->GetLargestRawFaviconForPageURL(
226 GURL(ConvertJavaStringToUTF16(env, j_page_url)),
227 icon_types,
228 static_cast<int>(j_min_size_threshold_px),
229 callback_runner,
230 cancelable_task_tracker_.get());
233 ScopedJavaLocalRef<jobject> FaviconHelper::GetSyncedFaviconImageForURL(
234 JNIEnv* env,
235 jobject obj,
236 jobject jprofile,
237 jstring j_page_url) {
238 Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
239 DCHECK(profile);
241 std::string page_url = ConvertJavaStringToUTF8(env, j_page_url);
243 ProfileSyncService* sync_service =
244 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
245 DCHECK(sync_service);
247 scoped_refptr<base::RefCountedMemory> favicon_png;
248 sync_driver::OpenTabsUIDelegate* open_tabs =
249 sync_service->GetOpenTabsUIDelegate();
250 DCHECK(open_tabs);
252 if (!open_tabs->GetSyncedFaviconForPageURL(page_url, &favicon_png))
253 return ScopedJavaLocalRef<jobject>();
255 // Convert favicon_image_result to java objects.
256 gfx::Image favicon_image = gfx::Image::CreateFrom1xPNGBytes(favicon_png);
257 SkBitmap favicon_bitmap = favicon_image.AsBitmap();
259 ScopedJavaLocalRef<jobject> j_favicon_bitmap;
260 if (favicon_bitmap.isNull())
261 return ScopedJavaLocalRef<jobject>();
263 return gfx::ConvertToJavaBitmap(&favicon_bitmap);
266 void FaviconHelper::EnsureFaviconIsAvailable(
267 JNIEnv* env,
268 jobject obj,
269 jobject j_profile,
270 jobject j_web_contents,
271 jstring j_page_url,
272 jstring j_favicon_url,
273 jobject j_availability_callback) {
274 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
275 DCHECK(profile);
276 content::WebContents* web_contents =
277 content::WebContents::FromJavaWebContents(j_web_contents);
278 DCHECK(web_contents);
279 GURL page_url(ConvertJavaStringToUTF8(env, j_page_url));
280 GURL favicon_url(ConvertJavaStringToUTF8(env, j_favicon_url));
282 // TODO(treib): Optimize this by creating a FaviconService::HasFavicon method
283 // so that we don't have to actually get the image.
284 ScopedJavaGlobalRef<jobject> j_scoped_callback(env, j_availability_callback);
285 favicon_base::FaviconImageCallback callback_runner =
286 base::Bind(&OnFaviconImageResultAvailable, j_scoped_callback,
287 profile, web_contents, page_url, favicon_url);
288 favicon::FaviconService* service = FaviconServiceFactory::GetForProfile(
289 profile, ServiceAccessType::IMPLICIT_ACCESS);
290 service->GetFaviconImageForPageURL(page_url, callback_runner,
291 cancelable_task_tracker_.get());
294 FaviconHelper::~FaviconHelper() {}
296 static jint GetDominantColorForBitmap(JNIEnv* env,
297 jclass clazz,
298 jobject bitmap) {
299 if (!bitmap)
300 return 0;
302 gfx::JavaBitmap bitmap_lock(bitmap);
303 SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(bitmap_lock);
304 return color_utils::CalculateKMeanColorOfBitmap(skbitmap);
307 // static
308 bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
309 return RegisterNativesImpl(env);