// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/commerce/merchant_viewer/merchant_signal_db.h"
#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/containers/fixed_flat_map.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "chrome/browser/persisted_state_db/session_proto_db_factory.h"
#include "components/commerce/core/proto/merchant_signal_db_content.pb.h"
#include "content/public/browser/android/browser_context_handle.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/commerce/merchant_viewer/android/jni_headers/MerchantTrustSignalsEventStorage_jni.h"
#include "chrome/browser/commerce/merchant_viewer/android/jni_headers/MerchantTrustSignalsEvent_jni.h"
namespace {
using MerchantSignalProto = merchant_signal_db::MerchantSignalContentProto;
using MerchantSignals =
std::vector<SessionProtoDB<MerchantSignalProto>::KeyAndValue>;
void OnLoadCallbackSingleEntry(const base::android::JavaRef<jobject>& jcallback,
bool success,
MerchantSignals data) {
DCHECK(success) << "There was an error loading from MerchantSignalDB";
if (data.size() == 0) {
base::android::RunObjectCallbackAndroid(jcallback, nullptr);
return;
}
DCHECK(data.size() == 1);
MerchantSignalProto proto = std::move(data.at(0).second);
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> signal =
Java_MerchantTrustSignalsEvent_Constructor(
env, base::android::ConvertUTF8ToJavaString(env, proto.key()) /*key*/,
proto.trust_signals_message_displayed_timestamp() /*timestamp*/);
base::android::RunObjectCallbackAndroid(jcallback, signal);
}
void OnLoadCallbackMultipleEntry(
const base::android::JavaRef<jobject>& jcallback,
bool success,
MerchantSignals data) {
DCHECK(success) << "There was an error loading from MerchantSignalDB";
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> jlist =
Java_MerchantTrustSignalsEvent_createEventList(env);
for (SessionProtoDB<MerchantSignalProto>::KeyAndValue& kv : data) {
MerchantSignalProto proto = std::move(kv.second);
Java_MerchantTrustSignalsEvent_createEventAndAddToList(
env, jlist,
base::android::ConvertUTF8ToJavaString(env, proto.key()) /*key*/,
proto.trust_signals_message_displayed_timestamp() /*timestamp*/);
}
base::android::RunObjectCallbackAndroid(jcallback, jlist);
}
void OnUpdateCallback(
const base::android::JavaRef<jobject>& joncomplete_for_testing,
bool success) {
DCHECK(success) << "There was an error modifying MerchantSignalDB";
if (joncomplete_for_testing)
base::android::RunRunnableAndroid(joncomplete_for_testing);
}
} // namespace
MerchantSignalDB::MerchantSignalDB(content::BrowserContext* browser_context)
: proto_db_(SessionProtoDBFactory<MerchantSignalProto>::GetInstance()
->GetForProfile(browser_context)) {}
MerchantSignalDB::~MerchantSignalDB() = default;
void MerchantSignalDB::Save(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey,
const jlong jtimestamp,
const base::android::JavaParamRef<jobject>& jcallback) {
const std::string& key = base::android::ConvertJavaStringToUTF8(env, jkey);
MerchantSignalProto proto;
proto.set_key(key);
proto.set_trust_signals_message_displayed_timestamp(jtimestamp);
proto_db_->InsertContent(
key, proto,
base::BindOnce(&OnUpdateCallback,
base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
}
void MerchantSignalDB::Load(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey,
const base::android::JavaParamRef<jobject>& jcallback) {
proto_db_->LoadOneEntry(
base::android::ConvertJavaStringToUTF8(env, jkey),
base::BindOnce(&OnLoadCallbackSingleEntry,
base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
}
void MerchantSignalDB::LoadWithPrefix(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jprefix,
const base::android::JavaParamRef<jobject>& jcallback) {
proto_db_->LoadContentWithPrefix(
base::android::ConvertJavaStringToUTF8(env, jprefix),
base::BindOnce(&OnLoadCallbackMultipleEntry,
base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
}
void MerchantSignalDB::Delete(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jkey,
const base::android::JavaParamRef<jobject>& joncomplete_for_testing) {
proto_db_->DeleteOneEntry(
base::android::ConvertJavaStringToUTF8(env, jkey),
base::BindOnce(&OnUpdateCallback,
base::android::ScopedJavaGlobalRef<jobject>(
joncomplete_for_testing)));
}
void MerchantSignalDB::DeleteAll(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& joncomplete_for_testing) {
proto_db_->DeleteAllContent(base::BindOnce(
&OnUpdateCallback,
base::android::ScopedJavaGlobalRef<jobject>(joncomplete_for_testing)));
}
static void JNI_MerchantTrustSignalsEventStorage_Init(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& jprofile) {
Java_MerchantTrustSignalsEventStorage_setNativePtr(
env, obj,
reinterpret_cast<intptr_t>(new MerchantSignalDB(
content::BrowserContextFromJavaHandle(jprofile))));
}