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/favicon_helper.h" 6 7 #include <jni.h> 8 9 #include "base/android/jni_android.h" 10 #include "base/android/jni_array.h" 11 #include "base/android/jni_string.h" 12 #include "base/android/scoped_java_ref.h" 13 #include "base/bind.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "chrome/browser/favicon/favicon_service.h" 17 #include "chrome/browser/favicon/favicon_service_factory.h" 18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile_android.h" 20 #include "chrome/browser/sync/open_tabs_ui_delegate.h" 21 #include "chrome/browser/sync/profile_sync_service.h" 22 #include "chrome/browser/sync/profile_sync_service_factory.h" 23 #include "chrome/browser/sync/profile_sync_service_factory.h" 24 #include "jni/FaviconHelper_jni.h" 25 #include "third_party/skia/include/core/SkBitmap.h" 26 #include "ui/gfx/android/java_bitmap.h" 27 #include "ui/gfx/codec/png_codec.h" 28 #include "ui/gfx/color_analysis.h" 29 #include "ui/gfx/color_utils.h" 30 31 using base::android::ScopedJavaGlobalRef; 32 using base::android::ScopedJavaLocalRef; 33 using base::android::AttachCurrentThread; 34 using base::android::ConvertJavaStringToUTF16; 35 using base::android::ConvertJavaStringToUTF8; 36 using base::android::ConvertUTF8ToJavaString; 37 38 namespace { 39 40 void OnLocalFaviconAvailable( 41 ScopedJavaGlobalRef<jobject>* j_favicon_image_callback, 42 const favicon_base::FaviconRawBitmapResult& result) { 43 JNIEnv* env = AttachCurrentThread(); 44 45 // Convert favicon_image_result to java objects. 46 ScopedJavaLocalRef<jstring> j_icon_url = 47 ConvertUTF8ToJavaString(env, result.icon_url.spec()); 48 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 49 if (result.is_valid()) { 50 SkBitmap favicon_bitmap; 51 gfx::PNGCodec::Decode(result.bitmap_data->front(), 52 result.bitmap_data->size(), 53 &favicon_bitmap); 54 if (!favicon_bitmap.isNull()) 55 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); 56 } 57 58 // Call java side OnLocalFaviconAvailable method. 59 Java_FaviconImageCallback_onFaviconAvailable(env, 60 j_favicon_image_callback->obj(), 61 j_favicon_bitmap.obj(), 62 j_icon_url.obj()); 63 } 64 65 void OnFaviconRawBitmapResultAvailable( 66 ScopedJavaGlobalRef<jobject>* j_favicon_image_callback, 67 const favicon_base::FaviconRawBitmapResult& favicon_bitmap_result) { 68 JNIEnv* env = AttachCurrentThread(); 69 70 // Convert favicon_image_result to java objects. 71 ScopedJavaLocalRef<jstring> j_icon_url = 72 ConvertUTF8ToJavaString(env, favicon_bitmap_result.icon_url.spec()); 73 74 SkBitmap favicon_bitmap; 75 if (favicon_bitmap_result.is_valid()) { 76 gfx::PNGCodec::Decode(favicon_bitmap_result.bitmap_data->front(), 77 favicon_bitmap_result.bitmap_data->size(), 78 &favicon_bitmap); 79 } 80 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 81 if (!favicon_bitmap.isNull()) 82 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); 83 84 // Call java side OnLocalFaviconAvailable method. 85 Java_FaviconImageCallback_onFaviconAvailable(env, 86 j_favicon_image_callback->obj(), 87 j_favicon_bitmap.obj(), 88 j_icon_url.obj()); 89 } 90 91 } // namespace 92 93 static jlong Init(JNIEnv* env, jclass clazz) { 94 return reinterpret_cast<intptr_t>(new FaviconHelper()); 95 } 96 97 FaviconHelper::FaviconHelper() { 98 cancelable_task_tracker_.reset(new base::CancelableTaskTracker()); 99 } 100 101 void FaviconHelper::Destroy(JNIEnv* env, jobject obj) { 102 delete this; 103 } 104 105 jboolean FaviconHelper::GetLocalFaviconImageForURL( 106 JNIEnv* env, 107 jobject obj, 108 jobject j_profile, 109 jstring j_page_url, 110 jint j_icon_types, 111 jint j_desired_size_in_pixel, 112 jobject j_favicon_image_callback) { 113 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); 114 DCHECK(profile); 115 if (!profile) 116 return false; 117 118 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 119 profile, Profile::EXPLICIT_ACCESS); 120 DCHECK(favicon_service); 121 if (!favicon_service) 122 return false; 123 124 ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback = 125 new ScopedJavaGlobalRef<jobject>(); 126 j_scoped_favicon_callback->Reset(env, j_favicon_image_callback); 127 128 favicon_base::FaviconRawBitmapCallback callback_runner = base::Bind( 129 &OnLocalFaviconAvailable, base::Owned(j_scoped_favicon_callback)); 130 131 favicon_service->GetRawFaviconForPageURL( 132 GURL(ConvertJavaStringToUTF16(env, j_page_url)), 133 static_cast<int>(j_icon_types), 134 static_cast<int>(j_desired_size_in_pixel), 135 callback_runner, 136 cancelable_task_tracker_.get()); 137 138 return true; 139 } 140 141 void FaviconHelper::GetLargestRawFaviconForUrl( 142 JNIEnv* env, 143 jobject obj, 144 jobject j_profile, 145 jstring j_page_url, 146 jintArray j_icon_types, 147 jint j_min_size_threshold_px, 148 jobject j_favicon_image_callback) { 149 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); 150 DCHECK(profile); 151 if (!profile) 152 return; 153 154 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 155 profile, Profile::EXPLICIT_ACCESS); 156 DCHECK(favicon_service); 157 if (!favicon_service) 158 return; 159 160 std::vector<int> icon_types; 161 base::android::JavaIntArrayToIntVector(env, j_icon_types, &icon_types); 162 163 ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback = 164 new ScopedJavaGlobalRef<jobject>(); 165 j_scoped_favicon_callback->Reset(env, j_favicon_image_callback); 166 167 favicon_base::FaviconRawBitmapCallback callback_runner = 168 base::Bind(&OnFaviconRawBitmapResultAvailable, 169 base::Owned(j_scoped_favicon_callback)); 170 favicon_service->GetLargestRawFaviconForPageURL( 171 GURL(ConvertJavaStringToUTF16(env, j_page_url)), 172 icon_types, 173 static_cast<int>(j_min_size_threshold_px), 174 callback_runner, 175 cancelable_task_tracker_.get()); 176 } 177 178 ScopedJavaLocalRef<jobject> FaviconHelper::GetSyncedFaviconImageForURL( 179 JNIEnv* env, 180 jobject obj, 181 jobject jprofile, 182 jstring j_page_url) { 183 Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); 184 DCHECK(profile); 185 186 std::string page_url = ConvertJavaStringToUTF8(env, j_page_url); 187 188 ProfileSyncService* sync_service = 189 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); 190 DCHECK(sync_service); 191 192 scoped_refptr<base::RefCountedMemory> favicon_png; 193 browser_sync::OpenTabsUIDelegate* open_tabs = 194 sync_service->GetOpenTabsUIDelegate(); 195 DCHECK(open_tabs); 196 197 if (!open_tabs->GetSyncedFaviconForPageURL(page_url, &favicon_png)) 198 return ScopedJavaLocalRef<jobject>(); 199 200 // Convert favicon_image_result to java objects. 201 gfx::Image favicon_image = gfx::Image::CreateFrom1xPNGBytes(favicon_png); 202 SkBitmap favicon_bitmap = favicon_image.AsBitmap(); 203 204 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 205 if (favicon_bitmap.isNull()) 206 return ScopedJavaLocalRef<jobject>(); 207 208 return gfx::ConvertToJavaBitmap(&favicon_bitmap); 209 } 210 211 FaviconHelper::~FaviconHelper() {} 212 213 static jint GetDominantColorForBitmap(JNIEnv* env, 214 jclass clazz, 215 jobject bitmap) { 216 if (!bitmap) 217 return 0; 218 219 gfx::JavaBitmap bitmap_lock(bitmap); 220 SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(bitmap_lock); 221 return color_utils::CalculateKMeanColorOfBitmap(skbitmap); 222 } 223 224 // static 225 bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) { 226 return RegisterNativesImpl(env); 227 } 228