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"
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
;
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(),
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(),
71 void OnFaviconDownloaded(
72 const ScopedJavaGlobalRef
<jobject
>& j_availability_callback
,
75 int download_request_id
,
77 const GURL
& image_url
,
78 const std::vector
<SkBitmap
>& bitmaps
,
79 const std::vector
<gfx::Size
>& original_sizes
) {
80 bool success
= !bitmaps
.empty();
82 gfx::Image image
= gfx::Image(CreateFaviconImageSkia(bitmaps
,
86 favicon_base::SetFaviconColorSpace(&image
);
87 favicon::FaviconService
* service
= FaviconServiceFactory::GetForProfile(
88 profile
, ServiceAccessType::IMPLICIT_ACCESS
);
89 service
->SetFavicons(page_url
, image_url
, favicon_base::FAVICON
, image
);
92 JNIEnv
* env
= AttachCurrentThread();
93 Java_FaviconAvailabilityCallback_onFaviconAvailabilityChecked(
94 env
, j_availability_callback
.obj(), success
);
97 void OnFaviconImageResultAvailable(
98 const ScopedJavaGlobalRef
<jobject
>& j_availability_callback
,
100 content::WebContents
* web_contents
,
101 const GURL
& page_url
,
102 const GURL
& favicon_url
,
103 const favicon_base::FaviconImageResult
& result
) {
104 // If there already is a favicon, return immediately.
105 if (!result
.image
.IsEmpty()) {
106 JNIEnv
* env
= AttachCurrentThread();
107 Java_FaviconAvailabilityCallback_onFaviconAvailabilityChecked(
108 env
, j_availability_callback
.obj(), false);
112 web_contents
->DownloadImage(favicon_url
, true, 0, false,
113 base::Bind(OnFaviconDownloaded
,
114 j_availability_callback
,
120 static jlong
Init(JNIEnv
* env
, const JavaParamRef
<jclass
>& clazz
) {
121 return reinterpret_cast<intptr_t>(new FaviconHelper());
124 FaviconHelper::FaviconHelper() {
125 cancelable_task_tracker_
.reset(new base::CancelableTaskTracker());
128 void FaviconHelper::Destroy(JNIEnv
* env
, jobject obj
) {
132 jboolean
FaviconHelper::GetLocalFaviconImageForURL(
138 jint j_desired_size_in_pixel
,
139 jobject j_favicon_image_callback
) {
140 Profile
* profile
= ProfileAndroid::FromProfileAndroid(j_profile
);
145 favicon::FaviconService
* favicon_service
=
146 FaviconServiceFactory::GetForProfile(profile
,
147 ServiceAccessType::EXPLICIT_ACCESS
);
148 DCHECK(favicon_service
);
149 if (!favicon_service
)
152 ScopedJavaGlobalRef
<jobject
>* j_scoped_favicon_callback
=
153 new ScopedJavaGlobalRef
<jobject
>();
154 j_scoped_favicon_callback
->Reset(env
, j_favicon_image_callback
);
156 favicon_base::FaviconRawBitmapCallback callback_runner
= base::Bind(
157 &OnLocalFaviconAvailable
, base::Owned(j_scoped_favicon_callback
));
159 favicon_service
->GetRawFaviconForPageURL(
160 GURL(ConvertJavaStringToUTF16(env
, j_page_url
)),
161 static_cast<int>(j_icon_types
),
162 static_cast<int>(j_desired_size_in_pixel
),
164 cancelable_task_tracker_
.get());
169 ScopedJavaLocalRef
<jobject
> FaviconHelper::GetSyncedFaviconImageForURL(
173 jstring j_page_url
) {
174 Profile
* profile
= ProfileAndroid::FromProfileAndroid(jprofile
);
177 std::string page_url
= ConvertJavaStringToUTF8(env
, j_page_url
);
179 ProfileSyncService
* sync_service
=
180 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile
);
181 DCHECK(sync_service
);
183 scoped_refptr
<base::RefCountedMemory
> favicon_png
;
184 sync_driver::OpenTabsUIDelegate
* open_tabs
=
185 sync_service
->GetOpenTabsUIDelegate();
188 if (!open_tabs
->GetSyncedFaviconForPageURL(page_url
, &favicon_png
))
189 return ScopedJavaLocalRef
<jobject
>();
191 // Convert favicon_image_result to java objects.
192 gfx::Image favicon_image
= gfx::Image::CreateFrom1xPNGBytes(favicon_png
);
193 SkBitmap favicon_bitmap
= favicon_image
.AsBitmap();
195 ScopedJavaLocalRef
<jobject
> j_favicon_bitmap
;
196 if (favicon_bitmap
.isNull())
197 return ScopedJavaLocalRef
<jobject
>();
199 return gfx::ConvertToJavaBitmap(&favicon_bitmap
);
202 void FaviconHelper::EnsureFaviconIsAvailable(
206 jobject j_web_contents
,
208 jstring j_favicon_url
,
209 jobject j_availability_callback
) {
210 Profile
* profile
= ProfileAndroid::FromProfileAndroid(j_profile
);
212 content::WebContents
* web_contents
=
213 content::WebContents::FromJavaWebContents(j_web_contents
);
214 DCHECK(web_contents
);
215 GURL
page_url(ConvertJavaStringToUTF8(env
, j_page_url
));
216 GURL
favicon_url(ConvertJavaStringToUTF8(env
, j_favicon_url
));
218 // TODO(treib): Optimize this by creating a FaviconService::HasFavicon method
219 // so that we don't have to actually get the image.
220 ScopedJavaGlobalRef
<jobject
> j_scoped_callback(env
, j_availability_callback
);
221 favicon_base::FaviconImageCallback callback_runner
=
222 base::Bind(&OnFaviconImageResultAvailable
, j_scoped_callback
,
223 profile
, web_contents
, page_url
, favicon_url
);
224 favicon::FaviconService
* service
= FaviconServiceFactory::GetForProfile(
225 profile
, ServiceAccessType::IMPLICIT_ACCESS
);
226 service
->GetFaviconImageForPageURL(page_url
, callback_runner
,
227 cancelable_task_tracker_
.get());
230 FaviconHelper::~FaviconHelper() {}
232 static jint
GetDominantColorForBitmap(JNIEnv
* env
,
233 const JavaParamRef
<jclass
>& clazz
,
234 const JavaParamRef
<jobject
>& bitmap
) {
238 gfx::JavaBitmap
bitmap_lock(bitmap
);
239 SkBitmap skbitmap
= gfx::CreateSkBitmapFromJavaBitmap(bitmap_lock
);
240 return color_utils::CalculateKMeanColorOfBitmap(skbitmap
);
244 bool FaviconHelper::RegisterFaviconHelper(JNIEnv
* env
) {
245 return RegisterNativesImpl(env
);