blob: 66072cb90c4cd5c6ff6046d521fdc6144c89c077 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/feed/feed_offline_bridge.h"
#include <memory>
#include <utility>
#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/android/feed/feed_host_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "components/feed/content/feed_host_service.h"
#include "components/feed/core/content_metadata.h"
#include "jni/FeedOfflineBridge_jni.h"
using base::android::JavaRef;
using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
namespace feed {
static jlong JNI_FeedOfflineBridge_Init(
JNIEnv* env,
const JavaParamRef<jobject>& j_this,
const JavaParamRef<jobject>& j_profile) {
Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
FeedHostService* host_service =
FeedHostServiceFactory::GetForBrowserContext(profile);
return reinterpret_cast<intptr_t>(
new FeedOfflineBridge(j_this, host_service->GetOfflineHost()));
}
FeedOfflineBridge::FeedOfflineBridge(const JavaRef<jobject>& j_this,
FeedOfflineHost* offline_host)
: j_this_(ScopedJavaGlobalRef<jobject>(j_this)),
offline_host_(offline_host),
weak_factory_(this) {
DCHECK(offline_host_);
// The host guarantees to not invoke these callbacks until Initialize() exits.
// This is important because until the Java bridge's constructor finishes, any
// attempt to cross JNI from native to Java will fail.
offline_host_->Initialize(
base::BindRepeating(&FeedOfflineBridge::TriggerGetKnownContent,
weak_factory_.GetWeakPtr()),
base::BindRepeating(&FeedOfflineBridge::NotifyStatusChange,
weak_factory_.GetWeakPtr()));
}
FeedOfflineBridge::~FeedOfflineBridge() = default;
void FeedOfflineBridge::Destroy(JNIEnv* env, const JavaRef<jobject>& j_this) {
delete this;
}
ScopedJavaLocalRef<jobject> FeedOfflineBridge::GetOfflineId(
JNIEnv* env,
const JavaRef<jobject>& j_this,
const JavaRef<jstring>& j_url) {
std::string url = ConvertJavaStringToUTF8(env, j_url);
base::Optional<int64_t> id = offline_host_->GetOfflineId(url);
return id ? Java_FeedOfflineBridge_createLong(env, *id) : nullptr;
}
void FeedOfflineBridge::GetOfflineStatus(JNIEnv* env,
const JavaRef<jobject>& j_this,
const JavaRef<jobjectArray>& j_urls,
const JavaRef<jobject>& j_callback) {
std::vector<std::string> urls;
base::android::AppendJavaStringArrayToStringVector(env, j_urls, &urls);
ScopedJavaGlobalRef<jobject> callback(j_callback);
offline_host_->GetOfflineStatus(
std::move(urls), base::BindOnce(&FeedOfflineBridge::OnGetOfflineStatus,
weak_factory_.GetWeakPtr(), callback));
}
void FeedOfflineBridge::OnContentRemoved(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jobjectArray>& j_urls) {
std::vector<std::string> urls;
base::android::AppendJavaStringArrayToStringVector(env, j_urls, &urls);
offline_host_->OnContentRemoved(urls);
}
void FeedOfflineBridge::OnNewContentReceived(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_this) {
offline_host_->OnNewContentReceived();
}
void FeedOfflineBridge::OnNoListeners(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_this) {
offline_host_->OnNoListeners();
}
void FeedOfflineBridge::AppendContentMetadata(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_this,
const base::android::JavaRef<jstring>& j_url,
const base::android::JavaRef<jstring>& j_title,
const jlong j_time_published_ms,
const base::android::JavaRef<jstring>& j_image_url,
const base::android::JavaRef<jstring>& j_publisher,
const base::android::JavaRef<jstring>& j_favicon_url,
const base::android::JavaRef<jstring>& j_snippet) {
ContentMetadata metadata;
DCHECK(!j_url.is_null());
metadata.url = base::android::ConvertJavaStringToUTF8(env, j_url);
DCHECK(!j_title.is_null());
metadata.title = base::android::ConvertJavaStringToUTF8(env, j_title);
metadata.time_published = base::Time::FromJavaTime(j_time_published_ms);
if (!j_image_url.is_null()) {
metadata.image_url =
base::android::ConvertJavaStringToUTF8(env, j_image_url);
}
if (!j_publisher.is_null()) {
metadata.publisher =
base::android::ConvertJavaStringToUTF8(env, j_publisher);
}
if (!j_favicon_url.is_null()) {
metadata.favicon_url =
base::android::ConvertJavaStringToUTF8(env, j_favicon_url);
}
if (!j_snippet.is_null()) {
metadata.snippet = base::android::ConvertJavaStringToUTF8(env, j_snippet);
}
known_content_metadata_buffer_.push_back(std::move(metadata));
}
void FeedOfflineBridge::OnGetKnownContentDone(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_this) {
offline_host_->OnGetKnownContentDone(
std::move(known_content_metadata_buffer_));
}
void FeedOfflineBridge::TriggerGetKnownContent() {
DCHECK(known_content_metadata_buffer_.empty());
JNIEnv* env = base::android::AttachCurrentThread();
Java_FeedOfflineBridge_getKnownContent(env, j_this_);
}
void FeedOfflineBridge::NotifyStatusChange(const std::string& url,
bool available_offline) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> j_string =
base::android::ConvertUTF8ToJavaString(env, url);
Java_FeedOfflineBridge_notifyStatusChange(env, j_this_, j_string,
available_offline);
}
void FeedOfflineBridge::OnGetOfflineStatus(
ScopedJavaGlobalRef<jobject> callback,
std::vector<std::string> urls) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_urls =
base::android::ToJavaArrayOfStrings(env, urls);
RunObjectCallbackAndroid(callback, j_urls);
}
} // namespace feed