blob: f2474393096ffba191ffbfa549a8bfddbd0ef8b8 [file] [log] [blame]
// Copyright 2016 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/offline_pages/android/evaluation/offline_page_evaluation_bridge.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#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/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/offline_pages/android/background_scheduler_bridge.h"
#include "chrome/browser/offline_pages/android/evaluation/evaluation_test_scheduler.h"
#include "chrome/browser/offline_pages/background_loader_offliner.h"
#include "chrome/browser/offline_pages/offline_page_model_factory.h"
#include "chrome/browser/offline_pages/request_coordinator_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/common/chrome_constants.h"
#include "components/offline_pages/core/background/offliner.h"
#include "components/offline_pages/core/background/offliner_policy.h"
#include "components/offline_pages/core/background/request_coordinator.h"
#include "components/offline_pages/core/background/request_notifier.h"
#include "components/offline_pages/core/background/request_queue.h"
#include "components/offline_pages/core/background/request_queue_store.h"
#include "components/offline_pages/core/background/request_queue_store_sql.h"
#include "components/offline_pages/core/background/save_page_request.h"
#include "components/offline_pages/core/downloads/download_notifying_observer.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/offline_page_model.h"
#include "components/offline_pages/core/offline_pages_ukm_reporter.h"
#include "content/public/browser/browser_context.h"
#include "jni/OfflinePageEvaluationBridge_jni.h"
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
namespace network {
class NetworkQualityTracker;
}
namespace offline_pages {
namespace android {
namespace {
const char kNativeTag[] = "OPNative";
const base::FilePath::CharType kTestRequestQueueDirname[] =
FILE_PATH_LITERAL("Offline Pages/test_request_queue");
void JNI_OfflinePageEvaluationBridge_ToJavaOfflinePageList(
JNIEnv* env,
const JavaRef<jobject>& j_result_obj,
const std::vector<OfflinePageItem>& offline_pages) {
for (const OfflinePageItem& offline_page : offline_pages) {
Java_OfflinePageEvaluationBridge_createOfflinePageAndAddToList(
env, j_result_obj,
ConvertUTF8ToJavaString(env, offline_page.url.spec()),
offline_page.offline_id,
ConvertUTF8ToJavaString(env, offline_page.client_id.name_space),
ConvertUTF8ToJavaString(env, offline_page.client_id.id),
ConvertUTF16ToJavaString(env, offline_page.title),
ConvertUTF8ToJavaString(env, offline_page.file_path.value()),
offline_page.file_size, offline_page.creation_time.ToJavaTime(),
offline_page.access_count, offline_page.last_access_time.ToJavaTime(),
ConvertUTF8ToJavaString(env, offline_page.request_origin));
}
}
ScopedJavaLocalRef<jobject>
JNI_OfflinePageEvaluationBridge_ToJavaSavePageRequest(
JNIEnv* env,
const SavePageRequest& request) {
return Java_OfflinePageEvaluationBridge_createSavePageRequest(
env, static_cast<int>(request.request_state()), request.request_id(),
ConvertUTF8ToJavaString(env, request.url().spec()),
ConvertUTF8ToJavaString(env, request.client_id().name_space),
ConvertUTF8ToJavaString(env, request.client_id().id));
}
ScopedJavaLocalRef<jobjectArray>
JNI_OfflinePageEvaluationBridge_CreateJavaSavePageRequests(
JNIEnv* env,
std::vector<std::unique_ptr<SavePageRequest>> requests) {
ScopedJavaLocalRef<jclass> save_page_request_clazz = base::android::GetClass(
env, "org/chromium/chrome/browser/offlinepages/SavePageRequest");
jobjectArray joa = env->NewObjectArray(
requests.size(), save_page_request_clazz.obj(), nullptr);
base::android::CheckException(env);
for (size_t i = 0; i < requests.size(); i++) {
SavePageRequest request = *(requests[i]);
ScopedJavaLocalRef<jobject> j_save_page_request =
JNI_OfflinePageEvaluationBridge_ToJavaSavePageRequest(env, request);
env->SetObjectArrayElement(joa, i, j_save_page_request.obj());
}
return ScopedJavaLocalRef<jobjectArray>(env, joa);
}
void GetAllPagesCallback(
const ScopedJavaGlobalRef<jobject>& j_result_obj,
const ScopedJavaGlobalRef<jobject>& j_callback_obj,
const OfflinePageModel::MultipleOfflinePageItemResult& result) {
JNIEnv* env = base::android::AttachCurrentThread();
JNI_OfflinePageEvaluationBridge_ToJavaOfflinePageList(env, j_result_obj,
result);
base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj);
}
void OnGetAllRequestsDone(
const ScopedJavaGlobalRef<jobject>& j_callback_obj,
std::vector<std::unique_ptr<SavePageRequest>> all_requests) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_result_obj =
JNI_OfflinePageEvaluationBridge_CreateJavaSavePageRequests(
env, std::move(all_requests));
base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj);
}
void OnRemoveRequestsDone(const ScopedJavaGlobalRef<jobject>& j_callback_obj,
const MultipleItemStatuses& removed_request_results) {
base::android::RunIntCallbackAndroid(
j_callback_obj, static_cast<int>(removed_request_results.size()));
}
std::unique_ptr<KeyedService> GetTestingRequestCoordinator(
content::BrowserContext* context,
std::unique_ptr<OfflinerPolicy> policy,
std::unique_ptr<Offliner> offliner) {
scoped_refptr<base::SequencedTaskRunner> background_task_runner =
base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
Profile* profile = Profile::FromBrowserContext(context);
base::FilePath queue_store_path =
profile->GetPath().Append(kTestRequestQueueDirname);
std::unique_ptr<RequestQueueStoreSQL> queue_store(
new RequestQueueStoreSQL(background_task_runner, queue_store_path));
std::unique_ptr<RequestQueue> queue(new RequestQueue(std::move(queue_store)));
std::unique_ptr<android::EvaluationTestScheduler> scheduler(
new android::EvaluationTestScheduler());
network::NetworkQualityTracker* network_quality_tracker =
g_browser_process->network_quality_tracker();
std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter(
new OfflinePagesUkmReporter());
std::unique_ptr<RequestCoordinator> request_coordinator =
std::make_unique<RequestCoordinator>(
std::move(policy), std::move(offliner), std::move(queue),
std::move(scheduler), network_quality_tracker,
std::move(ukm_reporter));
request_coordinator->SetInternalStartProcessingCallbackForTest(
base::Bind(&android::EvaluationTestScheduler::ImmediateScheduleCallback,
base::Unretained(scheduler.get())));
return std::move(request_coordinator);
}
std::unique_ptr<KeyedService> GetTestBackgroundLoaderRequestCoordinator(
content::BrowserContext* context) {
std::unique_ptr<OfflinerPolicy> policy(new OfflinerPolicy());
std::unique_ptr<Offliner> offliner(new BackgroundLoaderOffliner(
context, policy.get(),
OfflinePageModelFactory::GetForBrowserContext(context),
nullptr)); // no need to connect LoadTerminationListener for harness.
return GetTestingRequestCoordinator(context, std::move(policy),
std::move(offliner));
}
RequestCoordinator* GetRequestCoordinator(Profile* profile,
bool use_evaluation_scheduler) {
if (!use_evaluation_scheduler) {
return RequestCoordinatorFactory::GetForBrowserContext(profile);
}
return static_cast<RequestCoordinator*>(
RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
profile, &GetTestBackgroundLoaderRequestCoordinator));
}
} // namespace
static jlong JNI_OfflinePageEvaluationBridge_CreateBridgeForProfile(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_profile,
const jboolean j_use_evaluation_scheduler) {
Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
OfflinePageModel* offline_page_model =
OfflinePageModelFactory::GetForBrowserContext(profile);
RequestCoordinator* request_coordinator = GetRequestCoordinator(
profile, static_cast<bool>(j_use_evaluation_scheduler));
if (offline_page_model == nullptr || request_coordinator == nullptr)
return 0;
OfflinePageEvaluationBridge* bridge = new OfflinePageEvaluationBridge(
env, obj, profile, offline_page_model, request_coordinator);
return reinterpret_cast<jlong>(bridge);
}
OfflinePageEvaluationBridge::OfflinePageEvaluationBridge(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
content::BrowserContext* browser_context,
OfflinePageModel* offline_page_model,
RequestCoordinator* request_coordinator)
: weak_java_ref_(env, obj),
browser_context_(browser_context),
offline_page_model_(offline_page_model),
request_coordinator_(request_coordinator) {
DCHECK(offline_page_model_);
DCHECK(request_coordinator_);
NotifyIfDoneLoading();
offline_page_model_->AddObserver(this);
request_coordinator_->AddObserver(this);
offline_page_model_->GetLogger()->SetClient(this);
request_coordinator_->GetLogger()->SetClient(this);
}
OfflinePageEvaluationBridge::~OfflinePageEvaluationBridge() {}
void OfflinePageEvaluationBridge::Destroy(JNIEnv* env,
const JavaParamRef<jobject>&) {
offline_page_model_->RemoveObserver(this);
request_coordinator_->RemoveObserver(this);
delete this;
}
// Implement OfflinePageModel::Observer
void OfflinePageEvaluationBridge::OfflinePageModelLoaded(
OfflinePageModel* model) {
DCHECK_EQ(offline_page_model_, model);
NotifyIfDoneLoading();
}
void OfflinePageEvaluationBridge::OfflinePageAdded(
OfflinePageModel* model,
const OfflinePageItem& added_page) {}
void OfflinePageEvaluationBridge::OfflinePageDeleted(
const OfflinePageModel::DeletedPageInfo& page_info) {}
// Implement RequestCoordinator::Observer
void OfflinePageEvaluationBridge::OnAdded(const SavePageRequest& request) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
if (obj.is_null())
return;
Java_OfflinePageEvaluationBridge_savePageRequestAdded(
env, obj,
JNI_OfflinePageEvaluationBridge_ToJavaSavePageRequest(env, request));
}
void OfflinePageEvaluationBridge::OnCompleted(
const SavePageRequest& request,
RequestNotifier::BackgroundSavePageResult status) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
if (obj.is_null())
return;
Java_OfflinePageEvaluationBridge_savePageRequestCompleted(
env, obj,
JNI_OfflinePageEvaluationBridge_ToJavaSavePageRequest(env, request),
static_cast<int>(status));
}
void OfflinePageEvaluationBridge::OnChanged(const SavePageRequest& request) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
if (obj.is_null())
return;
Java_OfflinePageEvaluationBridge_savePageRequestChanged(
env, obj,
JNI_OfflinePageEvaluationBridge_ToJavaSavePageRequest(env, request));
}
void OfflinePageEvaluationBridge::OnNetworkProgress(
const SavePageRequest& request,
int64_t received_bytes) {}
void OfflinePageEvaluationBridge::CustomLog(const std::string& message) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
if (obj.is_null())
return;
Java_OfflinePageEvaluationBridge_log(env, obj,
ConvertUTF8ToJavaString(env, kNativeTag),
ConvertUTF8ToJavaString(env, message));
}
void OfflinePageEvaluationBridge::GetAllPages(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_result_obj,
const JavaParamRef<jobject>& j_callback_obj) {
DCHECK(j_result_obj);
DCHECK(j_callback_obj);
ScopedJavaGlobalRef<jobject> j_result_ref(j_result_obj);
ScopedJavaGlobalRef<jobject> j_callback_ref(j_callback_obj);
offline_page_model_->GetAllPages(
base::Bind(&GetAllPagesCallback, j_result_ref, j_callback_ref));
}
bool OfflinePageEvaluationBridge::PushRequestProcessing(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_callback_obj) {
ScopedJavaGlobalRef<jobject> j_callback_ref(j_callback_obj);
DCHECK(request_coordinator_);
base::android::RunBooleanCallbackAndroid(j_callback_obj, false);
return request_coordinator_->StartImmediateProcessing(base::BindRepeating(
&base::android::RunBooleanCallbackAndroid, j_callback_ref));
}
void OfflinePageEvaluationBridge::SavePageLater(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& j_url,
const JavaParamRef<jstring>& j_namespace,
const JavaParamRef<jstring>& j_client_id,
jboolean user_requested) {
offline_pages::ClientId client_id;
client_id.name_space = ConvertJavaStringToUTF8(env, j_namespace);
client_id.id = ConvertJavaStringToUTF8(env, j_client_id);
RequestCoordinator::SavePageLaterParams params;
params.url = GURL(ConvertJavaStringToUTF8(env, j_url));
params.client_id = client_id;
params.user_requested = static_cast<bool>(user_requested);
request_coordinator_->SavePageLater(params);
}
void OfflinePageEvaluationBridge::GetRequestsInQueue(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& j_callback_obj) {
ScopedJavaGlobalRef<jobject> j_callback_ref(j_callback_obj);
request_coordinator_->GetAllRequests(
base::Bind(&OnGetAllRequestsDone, j_callback_ref));
}
void OfflinePageEvaluationBridge::RemoveRequestsFromQueue(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jlongArray>& j_request_ids,
const JavaParamRef<jobject>& j_callback_obj) {
std::vector<int64_t> request_ids;
base::android::JavaLongArrayToInt64Vector(env, j_request_ids, &request_ids);
ScopedJavaGlobalRef<jobject> j_callback_ref(j_callback_obj);
request_coordinator_->RemoveRequests(
request_ids, base::Bind(&OnRemoveRequestsDone, j_callback_ref));
}
void OfflinePageEvaluationBridge::NotifyIfDoneLoading() const {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
if (obj.is_null())
return;
Java_OfflinePageEvaluationBridge_offlinePageModelLoaded(env, obj);
}
} // namespace android
} // namespace offline_pages