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::FaviconImageResult& favicon_image_result) { 43 JNIEnv* env = AttachCurrentThread(); 44 45 // Convert favicon_image_result to java objects. 46 ScopedJavaLocalRef<jstring> j_icon_url = 47 ConvertUTF8ToJavaString(env, favicon_image_result.icon_url.spec()); 48 SkBitmap favicon_bitmap = favicon_image_result.image.AsBitmap(); 49 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 50 if (!favicon_bitmap.isNull()) 51 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); 52 53 // Call java side OnLocalFaviconAvailable method. 54 Java_FaviconImageCallback_onFaviconAvailable(env, 55 j_favicon_image_callback->obj(), 56 j_favicon_bitmap.obj(), 57 j_icon_url.obj()); 58 } 59 60 void OnFaviconRawBitmapResultAvailable( 61 ScopedJavaGlobalRef<jobject>* j_favicon_image_callback, 62 const favicon_base::FaviconRawBitmapResult& favicon_bitmap_result) { 63 JNIEnv* env = AttachCurrentThread(); 64 65 // Convert favicon_image_result to java objects. 66 ScopedJavaLocalRef<jstring> j_icon_url = 67 ConvertUTF8ToJavaString(env, favicon_bitmap_result.icon_url.spec()); 68 69 SkBitmap favicon_bitmap; 70 if (favicon_bitmap_result.is_valid()) { 71 gfx::PNGCodec::Decode(favicon_bitmap_result.bitmap_data->front(), 72 favicon_bitmap_result.bitmap_data->size(), 73 &favicon_bitmap); 74 } 75 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 76 if (!favicon_bitmap.isNull()) 77 j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); 78 79 // Call java side OnLocalFaviconAvailable method. 80 Java_FaviconImageCallback_onFaviconAvailable(env, 81 j_favicon_image_callback->obj(), 82 j_favicon_bitmap.obj(), 83 j_icon_url.obj()); 84 } 85 86 } // namespace 87 88 static jlong Init(JNIEnv* env, jclass clazz) { 89 return reinterpret_cast<intptr_t>(new FaviconHelper()); 90 } 91 92 FaviconHelper::FaviconHelper() { 93 cancelable_task_tracker_.reset(new base::CancelableTaskTracker()); 94 } 95 96 void FaviconHelper::Destroy(JNIEnv* env, jobject obj) { 97 delete this; 98 } 99 100 jboolean FaviconHelper::GetLocalFaviconImageForURL( 101 JNIEnv* env, 102 jobject obj, 103 jobject j_profile, 104 jstring j_page_url, 105 jint j_icon_types, 106 jint j_desired_size_in_dip, 107 jobject j_favicon_image_callback) { 108 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); 109 DCHECK(profile); 110 if (!profile) 111 return false; 112 113 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 114 profile, Profile::EXPLICIT_ACCESS); 115 DCHECK(favicon_service); 116 if (!favicon_service) 117 return false; 118 119 FaviconService::FaviconForPageURLParams params( 120 GURL(ConvertJavaStringToUTF16(env, j_page_url)), 121 static_cast<int>(j_icon_types), 122 static_cast<int>(j_desired_size_in_dip)); 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::FaviconImageCallback callback_runner = base::Bind( 129 &OnLocalFaviconAvailable, base::Owned(j_scoped_favicon_callback)); 130 131 favicon_service->GetFaviconImageForPageURL( 132 params, callback_runner, 133 cancelable_task_tracker_.get()); 134 135 return true; 136 } 137 138 void FaviconHelper::GetLargestRawFaviconForUrl( 139 JNIEnv* env, 140 jobject obj, 141 jobject j_profile, 142 jstring j_page_url, 143 jintArray j_icon_types, 144 jint j_min_size_threshold_px, 145 jobject j_favicon_image_callback) { 146 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); 147 DCHECK(profile); 148 if (!profile) 149 return; 150 151 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 152 profile, Profile::EXPLICIT_ACCESS); 153 DCHECK(favicon_service); 154 if (!favicon_service) 155 return; 156 157 std::vector<int> icon_types; 158 base::android::JavaIntArrayToIntVector(env, j_icon_types, &icon_types); 159 160 ScopedJavaGlobalRef<jobject>* j_scoped_favicon_callback = 161 new ScopedJavaGlobalRef<jobject>(); 162 j_scoped_favicon_callback->Reset(env, j_favicon_image_callback); 163 164 favicon_base::FaviconRawBitmapCallback callback_runner = 165 base::Bind(&OnFaviconRawBitmapResultAvailable, 166 base::Owned(j_scoped_favicon_callback)); 167 favicon_service->GetLargestRawFaviconForPageURL( 168 profile, 169 GURL(ConvertJavaStringToUTF16(env, j_page_url)), 170 icon_types, 171 static_cast<int>(j_min_size_threshold_px), 172 callback_runner, 173 cancelable_task_tracker_.get()); 174 } 175 176 ScopedJavaLocalRef<jobject> FaviconHelper::GetSyncedFaviconImageForURL( 177 JNIEnv* env, 178 jobject obj, 179 jobject jprofile, 180 jstring j_page_url) { 181 Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); 182 DCHECK(profile); 183 184 std::string page_url = ConvertJavaStringToUTF8(env, j_page_url); 185 186 ProfileSyncService* sync_service = 187 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); 188 DCHECK(sync_service); 189 190 scoped_refptr<base::RefCountedMemory> favicon_png; 191 browser_sync::OpenTabsUIDelegate* open_tabs = 192 sync_service->GetOpenTabsUIDelegate(); 193 DCHECK(open_tabs); 194 195 if (!open_tabs->GetSyncedFaviconForPageURL(page_url, &favicon_png)) 196 return ScopedJavaLocalRef<jobject>(); 197 198 // Convert favicon_image_result to java objects. 199 gfx::Image favicon_image = gfx::Image::CreateFrom1xPNGBytes(favicon_png); 200 SkBitmap favicon_bitmap = favicon_image.AsBitmap(); 201 202 ScopedJavaLocalRef<jobject> j_favicon_bitmap; 203 if (favicon_bitmap.isNull()) 204 return ScopedJavaLocalRef<jobject>(); 205 206 return gfx::ConvertToJavaBitmap(&favicon_bitmap); 207 } 208 209 FaviconHelper::~FaviconHelper() {} 210 211 static jint GetDominantColorForBitmap(JNIEnv* env, 212 jclass clazz, 213 jobject bitmap) { 214 if (!bitmap) 215 return 0; 216 217 gfx::JavaBitmap bitmap_lock(bitmap); 218 SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(bitmap_lock); 219 return color_utils::CalculateKMeanColorOfBitmap(skbitmap); 220 } 221 222 // static 223 bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) { 224 return RegisterNativesImpl(env); 225 } 226