1// Copyright 2014 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/logo_bridge.h"
6
7#include <jni.h>
8
9#include "base/android/jni_android.h"
10#include "base/android/jni_string.h"
11#include "base/android/scoped_java_ref.h"
12#include "base/bind.h"
13#include "chrome/browser/android/logo_service.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/profiles/profile_android.h"
16#include "components/search_provider_logos/logo_tracker.h"
17#include "jni/LogoBridge_jni.h"
18#include "third_party/skia/include/core/SkBitmap.h"
19#include "ui/gfx/android/java_bitmap.h"
20
21using base::android::ScopedJavaLocalRef;
22using base::android::ConvertUTF8ToJavaString;
23
24namespace {
25
26// Converts a C++ Logo to a Java Logo.
27ScopedJavaLocalRef<jobject> ConvertLogoToJavaObject(
28    JNIEnv* env,
29    const search_provider_logos::Logo* logo) {
30  if (!logo)
31    return ScopedJavaLocalRef<jobject>();
32
33  ScopedJavaLocalRef<jobject> j_bitmap = gfx::ConvertToJavaBitmap(&logo->image);
34
35  ScopedJavaLocalRef<jstring> j_on_click_url;
36  if (!logo->metadata.on_click_url.empty())
37    j_on_click_url = ConvertUTF8ToJavaString(env, logo->metadata.on_click_url);
38
39  ScopedJavaLocalRef<jstring> j_alt_text;
40  if (!logo->metadata.alt_text.empty())
41    j_alt_text = ConvertUTF8ToJavaString(env, logo->metadata.alt_text);
42
43  return Java_LogoBridge_createLogo(
44      env, j_bitmap.obj(), j_on_click_url.obj(), j_alt_text.obj());
45}
46
47class LogoObserverAndroid : public search_provider_logos::LogoObserver {
48 public:
49  LogoObserverAndroid(base::WeakPtr<LogoBridge> logo_bridge,
50                      JNIEnv* env,
51                      jobject j_logo_observer)
52      : logo_bridge_(logo_bridge) {
53    j_logo_observer_.Reset(env, j_logo_observer);
54  }
55
56  virtual ~LogoObserverAndroid() {}
57
58  // seach_provider_logos::LogoObserver:
59  virtual void OnLogoAvailable(const search_provider_logos::Logo* logo,
60                               bool from_cache) OVERRIDE {
61    if (!logo_bridge_)
62      return;
63
64    JNIEnv* env = base::android::AttachCurrentThread();
65    ScopedJavaLocalRef<jobject> j_logo = ConvertLogoToJavaObject(env, logo);
66    Java_LogoObserver_onLogoAvailable(
67        env, j_logo_observer_.obj(), j_logo.obj(), from_cache);
68  }
69
70  virtual void OnObserverRemoved() OVERRIDE {
71    delete this;
72  }
73
74 private:
75  // The associated LogoBridge. We won't call back to Java if the LogoBridge has
76  // been destroyed.
77  base::WeakPtr<LogoBridge> logo_bridge_;
78
79  base::android::ScopedJavaGlobalRef<jobject> j_logo_observer_;
80};
81
82}  // namespace
83
84static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
85  LogoBridge* logo_bridge = new LogoBridge(j_profile);
86  return reinterpret_cast<intptr_t>(logo_bridge);
87}
88
89LogoBridge::LogoBridge(jobject j_profile) : weak_ptr_factory_(this) {
90  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
91  if (profile)
92    logo_service_ = LogoServiceFactory::GetForProfile(profile);
93}
94
95LogoBridge::~LogoBridge() {}
96
97void LogoBridge::Destroy(JNIEnv* env, jobject obj) {
98  delete this;
99}
100
101void LogoBridge::GetCurrentLogo(JNIEnv* env,
102                                jobject obj,
103                                jobject j_logo_observer) {
104  if (!logo_service_)
105    return;
106
107  // |observer| is deleted in LogoObserverAndroid::OnObserverRemoved().
108  LogoObserverAndroid* observer = new LogoObserverAndroid(
109      weak_ptr_factory_.GetWeakPtr(), env, j_logo_observer);
110  logo_service_->GetLogo(observer);
111}
112
113// static
114bool RegisterLogoBridge(JNIEnv* env) {
115  return RegisterNativesImpl(env);
116}
117