OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/logo_bridge.h" | 5 #include "chrome/browser/android/logo_bridge.h" |
6 | 6 |
7 #include <jni.h> | 7 #include <jni.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
11 #include "base/android/jni_array.h" | 11 #include "base/android/jni_array.h" |
12 #include "base/android/jni_string.h" | 12 #include "base/android/jni_string.h" |
13 #include "base/android/scoped_java_ref.h" | 13 #include "base/android/scoped_java_ref.h" |
| 14 #include "base/bind.h" |
| 15 #include "base/feature_list.h" |
14 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
15 #include "chrome/browser/android/logo_service.h" | 17 #include "chrome/browser/android/logo_service.h" |
| 18 #include "chrome/browser/doodle/doodle_service_factory.h" |
16 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/profiles/profile_android.h" | 20 #include "chrome/browser/profiles/profile_android.h" |
| 21 #include "chrome/browser/search/suggestions/image_decoder_impl.h" |
| 22 #include "components/image_fetcher/image_fetcher_impl.h" |
18 #include "components/search_provider_logos/logo_tracker.h" | 23 #include "components/search_provider_logos/logo_tracker.h" |
19 #include "jni/LogoBridge_jni.h" | 24 #include "jni/LogoBridge_jni.h" |
20 #include "net/url_request/url_fetcher.h" | 25 #include "net/url_request/url_fetcher.h" |
21 #include "net/url_request/url_fetcher_delegate.h" | 26 #include "net/url_request/url_fetcher_delegate.h" |
22 #include "net/url_request/url_request_context_getter.h" | 27 #include "net/url_request/url_request_context_getter.h" |
23 #include "net/url_request/url_request_status.h" | 28 #include "net/url_request/url_request_status.h" |
24 #include "third_party/skia/include/core/SkBitmap.h" | 29 #include "third_party/skia/include/core/SkBitmap.h" |
25 #include "ui/gfx/android/java_bitmap.h" | 30 #include "ui/gfx/android/java_bitmap.h" |
| 31 #include "ui/gfx/image/image.h" |
26 #include "url/gurl.h" | 32 #include "url/gurl.h" |
27 | 33 |
28 using base::android::ConvertJavaStringToUTF8; | 34 using base::android::ConvertJavaStringToUTF8; |
29 using base::android::ConvertUTF8ToJavaString; | 35 using base::android::ConvertUTF8ToJavaString; |
30 using base::android::JavaParamRef; | 36 using base::android::JavaParamRef; |
31 using base::android::ScopedJavaLocalRef; | 37 using base::android::ScopedJavaLocalRef; |
32 using base::android::ToJavaByteArray; | 38 using base::android::ToJavaByteArray; |
33 | 39 |
34 namespace { | 40 namespace { |
35 | 41 |
| 42 const base::Feature kUseNewDoodleApi{"UseNewDoodleApi", |
| 43 base::FEATURE_DISABLED_BY_DEFAULT}; |
| 44 |
| 45 ScopedJavaLocalRef<jobject> MakeJavaLogo(JNIEnv* env, |
| 46 const SkBitmap* bitmap, |
| 47 const GURL& on_click_url, |
| 48 const std::string& alt_text, |
| 49 const GURL& animated_url) { |
| 50 ScopedJavaLocalRef<jobject> j_bitmap = gfx::ConvertToJavaBitmap(bitmap); |
| 51 |
| 52 ScopedJavaLocalRef<jstring> j_on_click_url; |
| 53 if (on_click_url.is_valid()) |
| 54 j_on_click_url = ConvertUTF8ToJavaString(env, on_click_url.spec()); |
| 55 |
| 56 ScopedJavaLocalRef<jstring> j_alt_text; |
| 57 if (!alt_text.empty()) |
| 58 j_alt_text = ConvertUTF8ToJavaString(env, alt_text); |
| 59 |
| 60 ScopedJavaLocalRef<jstring> j_animated_url; |
| 61 if (animated_url.is_valid()) |
| 62 j_animated_url = ConvertUTF8ToJavaString(env, animated_url.spec()); |
| 63 |
| 64 return Java_LogoBridge_createLogo(env, j_bitmap, j_on_click_url, j_alt_text, |
| 65 j_animated_url); |
| 66 } |
| 67 |
36 // Converts a C++ Logo to a Java Logo. | 68 // Converts a C++ Logo to a Java Logo. |
37 ScopedJavaLocalRef<jobject> ConvertLogoToJavaObject( | 69 ScopedJavaLocalRef<jobject> ConvertLogoToJavaObject( |
38 JNIEnv* env, | 70 JNIEnv* env, |
39 const search_provider_logos::Logo* logo) { | 71 const search_provider_logos::Logo* logo) { |
40 if (!logo) | 72 if (!logo) |
41 return ScopedJavaLocalRef<jobject>(); | 73 return ScopedJavaLocalRef<jobject>(); |
42 | 74 |
43 ScopedJavaLocalRef<jobject> j_bitmap = gfx::ConvertToJavaBitmap(&logo->image); | 75 return MakeJavaLogo(env, &logo->image, GURL(logo->metadata.on_click_url), |
44 | 76 logo->metadata.alt_text, |
45 ScopedJavaLocalRef<jstring> j_on_click_url; | 77 GURL(logo->metadata.animated_url)); |
46 if (!logo->metadata.on_click_url.empty()) | |
47 j_on_click_url = ConvertUTF8ToJavaString(env, logo->metadata.on_click_url); | |
48 | |
49 ScopedJavaLocalRef<jstring> j_alt_text; | |
50 if (!logo->metadata.alt_text.empty()) | |
51 j_alt_text = ConvertUTF8ToJavaString(env, logo->metadata.alt_text); | |
52 | |
53 ScopedJavaLocalRef<jstring> j_animated_url; | |
54 if (!logo->metadata.animated_url.empty()) | |
55 j_animated_url = ConvertUTF8ToJavaString(env, logo->metadata.animated_url); | |
56 | |
57 return Java_LogoBridge_createLogo(env, j_bitmap, j_on_click_url, j_alt_text, | |
58 j_animated_url); | |
59 } | 78 } |
60 | 79 |
61 class LogoObserverAndroid : public search_provider_logos::LogoObserver { | 80 class LogoObserverAndroid : public search_provider_logos::LogoObserver { |
62 public: | 81 public: |
63 LogoObserverAndroid(base::WeakPtr<LogoBridge> logo_bridge, | 82 LogoObserverAndroid(base::WeakPtr<LogoBridge> logo_bridge, |
64 JNIEnv* env, | 83 JNIEnv* env, |
65 jobject j_logo_observer) | 84 jobject j_logo_observer) |
66 : logo_bridge_(logo_bridge) { | 85 : logo_bridge_(logo_bridge) { |
67 j_logo_observer_.Reset(env, j_logo_observer); | 86 j_logo_observer_.Reset(env, j_logo_observer); |
68 } | 87 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 }; | 184 }; |
166 | 185 |
167 static jlong Init(JNIEnv* env, | 186 static jlong Init(JNIEnv* env, |
168 const JavaParamRef<jobject>& obj, | 187 const JavaParamRef<jobject>& obj, |
169 const JavaParamRef<jobject>& j_profile) { | 188 const JavaParamRef<jobject>& j_profile) { |
170 LogoBridge* logo_bridge = new LogoBridge(j_profile); | 189 LogoBridge* logo_bridge = new LogoBridge(j_profile); |
171 return reinterpret_cast<intptr_t>(logo_bridge); | 190 return reinterpret_cast<intptr_t>(logo_bridge); |
172 } | 191 } |
173 | 192 |
174 LogoBridge::LogoBridge(jobject j_profile) | 193 LogoBridge::LogoBridge(jobject j_profile) |
175 : logo_service_(nullptr), weak_ptr_factory_(this) { | 194 : logo_service_(nullptr), |
| 195 doodle_service_(nullptr), |
| 196 doodle_observer_(this), |
| 197 weak_ptr_factory_(this) { |
176 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); | 198 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); |
177 DCHECK(profile); | 199 DCHECK(profile); |
178 logo_service_ = LogoServiceFactory::GetForProfile(profile); | 200 |
| 201 if (base::FeatureList::IsEnabled(kUseNewDoodleApi)) { |
| 202 doodle_service_ = DoodleServiceFactory::GetForProfile(profile); |
| 203 image_fetcher_ = base::MakeUnique<image_fetcher::ImageFetcherImpl>( |
| 204 base::MakeUnique<suggestions::ImageDecoderImpl>(), |
| 205 profile->GetRequestContext()); |
| 206 |
| 207 doodle_observer_.Add(doodle_service_); |
| 208 } else { |
| 209 logo_service_ = LogoServiceFactory::GetForProfile(profile); |
| 210 } |
| 211 |
179 animated_logo_fetcher_ = base::MakeUnique<AnimatedLogoFetcher>( | 212 animated_logo_fetcher_ = base::MakeUnique<AnimatedLogoFetcher>( |
180 profile->GetRequestContext()); | 213 profile->GetRequestContext()); |
181 } | 214 } |
182 | 215 |
183 LogoBridge::~LogoBridge() {} | 216 LogoBridge::~LogoBridge() {} |
184 | 217 |
185 void LogoBridge::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 218 void LogoBridge::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
186 delete this; | 219 delete this; |
187 } | 220 } |
188 | 221 |
189 void LogoBridge::GetCurrentLogo(JNIEnv* env, | 222 void LogoBridge::GetCurrentLogo(JNIEnv* env, |
190 const JavaParamRef<jobject>& obj, | 223 const JavaParamRef<jobject>& obj, |
191 const JavaParamRef<jobject>& j_logo_observer) { | 224 const JavaParamRef<jobject>& j_logo_observer) { |
192 // |observer| is deleted in LogoObserverAndroid::OnObserverRemoved(). | 225 if (doodle_service_) { |
193 LogoObserverAndroid* observer = new LogoObserverAndroid( | 226 j_logo_observer_.Reset(j_logo_observer); |
194 weak_ptr_factory_.GetWeakPtr(), env, j_logo_observer); | 227 |
195 logo_service_->GetLogo(observer); | 228 // Immediately hand out any current cached config. |
| 229 DoodleConfigReceived(doodle_service_->config(), /*from_cache=*/true); |
| 230 // Also request a refresh, in case something changed. |
| 231 doodle_service_->Refresh(); |
| 232 } else { |
| 233 // |observer| is deleted in LogoObserverAndroid::OnObserverRemoved(). |
| 234 LogoObserverAndroid* observer = new LogoObserverAndroid( |
| 235 weak_ptr_factory_.GetWeakPtr(), env, j_logo_observer); |
| 236 logo_service_->GetLogo(observer); |
| 237 } |
196 } | 238 } |
197 | 239 |
198 void LogoBridge::GetAnimatedLogo(JNIEnv* env, | 240 void LogoBridge::GetAnimatedLogo(JNIEnv* env, |
199 const JavaParamRef<jobject>& obj, | 241 const JavaParamRef<jobject>& obj, |
200 const JavaParamRef<jobject>& j_callback, | 242 const JavaParamRef<jobject>& j_callback, |
201 const JavaParamRef<jstring>& j_url) { | 243 const JavaParamRef<jstring>& j_url) { |
202 GURL url = GURL(ConvertJavaStringToUTF8(env, j_url)); | 244 GURL url = GURL(ConvertJavaStringToUTF8(env, j_url)); |
203 animated_logo_fetcher_->Start(env, url, j_callback); | 245 animated_logo_fetcher_->Start(env, url, j_callback); |
204 } | 246 } |
205 | 247 |
| 248 void LogoBridge::OnDoodleConfigUpdated( |
| 249 const base::Optional<doodle::DoodleConfig>& maybe_doodle_config) { |
| 250 if (j_logo_observer_.is_null()) { |
| 251 return; |
| 252 } |
| 253 DoodleConfigReceived(maybe_doodle_config, /*from_cache=*/false); |
| 254 } |
| 255 |
| 256 void LogoBridge::DoodleConfigReceived( |
| 257 const base::Optional<doodle::DoodleConfig>& maybe_doodle_config, |
| 258 bool from_cache) { |
| 259 DCHECK(!j_logo_observer_.is_null()); |
| 260 |
| 261 if (!maybe_doodle_config.has_value()) { |
| 262 JNIEnv* env = base::android::AttachCurrentThread(); |
| 263 Java_LogoObserver_onLogoAvailable( |
| 264 env, j_logo_observer_, ScopedJavaLocalRef<jobject>(), from_cache); |
| 265 return; |
| 266 } |
| 267 const doodle::DoodleConfig& doodle_config = maybe_doodle_config.value(); |
| 268 // If there is a CTA image, that means the main image is animated. Show the |
| 269 // non-animated CTA image first, and load the animated one only when the |
| 270 // user requests it. |
| 271 bool has_cta = doodle_config.large_cta_image.has_value(); |
| 272 const GURL& image_url = has_cta ? doodle_config.large_cta_image->url |
| 273 : doodle_config.large_image.url; |
| 274 const GURL& animated_image_url = |
| 275 has_cta ? doodle_config.large_image.url : GURL::EmptyGURL(); |
| 276 // TODO(treib): For interactive doodles, use |fullpage_interactive_url| |
| 277 // instead of |target_url|? |
| 278 const GURL& on_click_url = doodle_config.target_url; |
| 279 const std::string& alt_text = doodle_config.alt_text; |
| 280 image_fetcher_->StartOrQueueNetworkRequest( |
| 281 image_url.spec(), image_url, |
| 282 base::Bind(&LogoBridge::DoodleImageFetched, base::Unretained(this), |
| 283 from_cache, on_click_url, alt_text, animated_image_url)); |
| 284 } |
| 285 |
| 286 void LogoBridge::DoodleImageFetched(bool config_from_cache, |
| 287 const GURL& on_click_url, |
| 288 const std::string& alt_text, |
| 289 const GURL& animated_image_url, |
| 290 const std::string& image_fetch_id, |
| 291 const gfx::Image& image) { |
| 292 JNIEnv* env = base::android::AttachCurrentThread(); |
| 293 |
| 294 if (image.IsEmpty()) { |
| 295 DLOG(WARNING) << "Failed to download doodle image"; |
| 296 Java_LogoObserver_onLogoAvailable(env, j_logo_observer_, |
| 297 ScopedJavaLocalRef<jobject>(), |
| 298 config_from_cache); |
| 299 return; |
| 300 } |
| 301 |
| 302 ScopedJavaLocalRef<jobject> j_logo = MakeJavaLogo( |
| 303 env, image.ToSkBitmap(), on_click_url, alt_text, animated_image_url); |
| 304 Java_LogoObserver_onLogoAvailable(env, j_logo_observer_, j_logo, |
| 305 config_from_cache); |
| 306 } |
| 307 |
206 // static | 308 // static |
207 bool RegisterLogoBridge(JNIEnv* env) { | 309 bool RegisterLogoBridge(JNIEnv* env) { |
208 return RegisterNativesImpl(env); | 310 return RegisterNativesImpl(env); |
209 } | 311 } |
OLD | NEW |