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
31using base::android::ScopedJavaGlobalRef;
32using base::android::ScopedJavaLocalRef;
33using base::android::AttachCurrentThread;
34using base::android::ConvertJavaStringToUTF16;
35using base::android::ConvertJavaStringToUTF8;
36using base::android::ConvertUTF8ToJavaString;
37
38namespace {
39
40void 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
65void 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
93static jlong Init(JNIEnv* env, jclass clazz) {
94  return reinterpret_cast<intptr_t>(new FaviconHelper());
95}
96
97FaviconHelper::FaviconHelper() {
98  cancelable_task_tracker_.reset(new base::CancelableTaskTracker());
99}
100
101void FaviconHelper::Destroy(JNIEnv* env, jobject obj) {
102  delete this;
103}
104
105jboolean 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
141void 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
178ScopedJavaLocalRef<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
211FaviconHelper::~FaviconHelper() {}
212
213static 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
225bool FaviconHelper::RegisterFaviconHelper(JNIEnv* env) {
226  return RegisterNativesImpl(env);
227}
228