blob: 8404e231144749dda1411647dd08a455892cd48c [file] [log] [blame]
// Copyright 2019 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/autofill_assistant/ui_controller_android_utils.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/notreached.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantColor_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDateTime_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDialogButton_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDimension_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDrawable_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantInfoPopup_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantValue_jni.h"
#include "components/autofill_assistant/browser/generic_ui_java_generated_enums.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill_assistant {
namespace ui_controller_android_utils {
namespace {
DrawableIcon MapDrawableIcon(DrawableProto::Icon icon) {
switch (icon) {
case DrawableProto::DRAWABLE_ICON_UNDEFINED:
return DrawableIcon::DRAWABLE_ICON_UNDEFINED;
case DrawableProto::PROGRESSBAR_DEFAULT_INITIAL_STEP:
return DrawableIcon::PROGRESSBAR_DEFAULT_INITIAL_STEP;
case DrawableProto::PROGRESSBAR_DEFAULT_DATA_COLLECTION:
return DrawableIcon::PROGRESSBAR_DEFAULT_DATA_COLLECTION;
case DrawableProto::PROGRESSBAR_DEFAULT_PAYMENT:
return DrawableIcon::PROGRESSBAR_DEFAULT_PAYMENT;
case DrawableProto::PROGRESSBAR_DEFAULT_FINAL_STEP:
return DrawableIcon::PROGRESSBAR_DEFAULT_FINAL_STEP;
case DrawableProto::SITTING_PERSON:
return DrawableIcon::SITTING_PERSON;
case DrawableProto::TICKET_STUB:
return DrawableIcon::TICKET_STUB;
case DrawableProto::SHOPPING_BASKET:
return DrawableIcon::SHOPPING_BASKET;
case DrawableProto::FAST_FOOD:
return DrawableIcon::FAST_FOOD;
case DrawableProto::LOCAL_DINING:
return DrawableIcon::LOCAL_DINING;
case DrawableProto::COGWHEEL:
return DrawableIcon::COGWHEEL;
case DrawableProto::KEY:
return DrawableIcon::KEY;
case DrawableProto::CAR:
return DrawableIcon::CAR;
case DrawableProto::GROCERY:
return DrawableIcon::GROCERY;
}
}
} // namespace
base::android::ScopedJavaLocalRef<jobject> GetJavaColor(
JNIEnv* env,
const std::string& color_string) {
if (!Java_AssistantColor_isValidColorString(
env, base::android::ConvertUTF8ToJavaString(env, color_string))) {
if (!color_string.empty()) {
VLOG(1) << "Encountered invalid color string: " << color_string;
}
return nullptr;
}
return Java_AssistantColor_createFromString(
env, base::android::ConvertUTF8ToJavaString(env, color_string));
}
base::android::ScopedJavaLocalRef<jobject> GetJavaColor(
JNIEnv* env,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const ColorProto& proto) {
switch (proto.color_case()) {
case ColorProto::kResourceIdentifier:
if (!Java_AssistantColor_isValidResourceIdentifier(
env, jcontext,
base::android::ConvertUTF8ToJavaString(
env, proto.resource_identifier()))) {
VLOG(1) << "Encountered invalid color resource identifier: "
<< proto.resource_identifier();
return nullptr;
}
return Java_AssistantColor_createFromResource(
env, jcontext,
base::android::ConvertUTF8ToJavaString(env,
proto.resource_identifier()));
case ColorProto::kParseableColor:
return GetJavaColor(env, proto.parseable_color());
case ColorProto::COLOR_NOT_SET:
return nullptr;
}
}
base::Optional<int> GetPixelSize(
JNIEnv* env,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const ClientDimensionProto& proto) {
switch (proto.size_case()) {
case ClientDimensionProto::kDp:
return Java_AssistantDimension_getPixelSizeDp(env, jcontext, proto.dp());
break;
case ClientDimensionProto::kWidthFactor:
return Java_AssistantDimension_getPixelSizeWidthFactor(
env, jcontext, proto.width_factor());
break;
case ClientDimensionProto::kHeightFactor:
return Java_AssistantDimension_getPixelSizeHeightFactor(
env, jcontext, proto.height_factor());
break;
case ClientDimensionProto::SIZE_NOT_SET:
return base::nullopt;
}
}
int GetPixelSizeOrDefault(
JNIEnv* env,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const ClientDimensionProto& proto,
int default_value) {
auto size = GetPixelSize(env, jcontext, proto);
if (size) {
return *size;
}
return default_value;
}
base::android::ScopedJavaLocalRef<jobject> CreateJavaDrawable(
JNIEnv* env,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const DrawableProto& proto) {
switch (proto.drawable_case()) {
case DrawableProto::kResourceIdentifier:
if (!Java_AssistantDrawable_isValidDrawableResource(
env, jcontext,
base::android::ConvertUTF8ToJavaString(
env, proto.resource_identifier()))) {
VLOG(1) << "Encountered invalid drawable resource identifier: "
<< proto.resource_identifier();
return nullptr;
}
return Java_AssistantDrawable_createFromResource(
env, base::android::ConvertUTF8ToJavaString(
env, proto.resource_identifier()));
case DrawableProto::kBitmap: {
int width_pixels = ui_controller_android_utils::GetPixelSizeOrDefault(
env, jcontext, proto.bitmap().width(), 0);
int height_pixels = ui_controller_android_utils::GetPixelSizeOrDefault(
env, jcontext, proto.bitmap().height(), 0);
return Java_AssistantDrawable_createFromUrl(
env,
base::android::ConvertUTF8ToJavaString(env, proto.bitmap().url()),
width_pixels, height_pixels);
}
case DrawableProto::kShape: {
switch (proto.shape().shape_case()) {
case ShapeDrawableProto::kRectangle: {
auto jbackground_color = ui_controller_android_utils::GetJavaColor(
env, jcontext, proto.shape().background_color());
auto jstroke_color = ui_controller_android_utils::GetJavaColor(
env, jcontext, proto.shape().stroke_color());
int stroke_width_pixels =
ui_controller_android_utils::GetPixelSizeOrDefault(
env, jcontext, proto.shape().stroke_width(), 0);
int corner_radius_pixels =
ui_controller_android_utils::GetPixelSizeOrDefault(
env, jcontext, proto.shape().rectangle().corner_radius(), 0);
return Java_AssistantDrawable_createRectangleShape(
env, jbackground_color, jstroke_color, stroke_width_pixels,
corner_radius_pixels);
break;
}
case ShapeDrawableProto::SHAPE_NOT_SET:
return nullptr;
}
}
case DrawableProto::kIcon: {
return Java_AssistantDrawable_createFromIcon(
env, static_cast<int>(MapDrawableIcon(proto.icon())));
}
case DrawableProto::kBase64: {
return Java_AssistantDrawable_createFromBase64(
env, base::android::ToJavaByteArray(env, proto.base64()));
}
case DrawableProto::DRAWABLE_NOT_SET:
return nullptr;
}
}
base::android::ScopedJavaLocalRef<jobject> ToJavaValue(
JNIEnv* env,
const ValueProto& proto) {
switch (proto.kind_case()) {
case ValueProto::kStrings: {
std::vector<std::string> strings;
strings.reserve(proto.strings().values_size());
for (const auto& string : proto.strings().values()) {
strings.push_back(string);
}
return Java_AssistantValue_createForStrings(
env, base::android::ToJavaArrayOfStrings(env, strings));
}
case ValueProto::kBooleans: {
auto booleans = std::make_unique<bool[]>(proto.booleans().values_size());
for (int i = 0; i < proto.booleans().values_size(); ++i) {
booleans[i] = proto.booleans().values()[i];
}
return Java_AssistantValue_createForBooleans(
env, base::android::ToJavaBooleanArray(
env, booleans.get(), proto.booleans().values_size()));
}
case ValueProto::kInts: {
auto ints = std::make_unique<int[]>(proto.ints().values_size());
for (int i = 0; i < proto.ints().values_size(); ++i) {
ints[i] = proto.ints().values()[i];
}
return Java_AssistantValue_createForIntegers(
env, base::android::ToJavaIntArray(env, ints.get(),
proto.ints().values_size()));
}
case ValueProto::kCreditCards:
case ValueProto::kProfiles:
case ValueProto::kLoginOptions:
case ValueProto::kCreditCardResponse:
case ValueProto::kServerPayload:
case ValueProto::kUserActions:
// Unused.
NOTREACHED();
return nullptr;
case ValueProto::kDates: {
auto jlist = Java_AssistantValue_createDateTimeList(env);
for (const auto& value : proto.dates().values()) {
Java_AssistantValue_addDateTimeToList(
env, jlist,
Java_AssistantDateTime_Constructor(
env, static_cast<int>(value.year()), value.month(), value.day(),
0, 0, 0));
}
return Java_AssistantValue_createForDateTimes(env, jlist);
}
case ValueProto::KIND_NOT_SET:
return Java_AssistantValue_create(env);
}
}
ValueProto ToNativeValue(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jvalue) {
ValueProto proto;
if (!jvalue) {
return proto;
}
auto jints = Java_AssistantValue_getIntegers(env, jvalue);
if (jints) {
auto* mutable_ints = proto.mutable_ints();
std::vector<int> ints;
base::android::JavaIntArrayToIntVector(env, jints, &ints);
for (int i : ints) {
mutable_ints->add_values(i);
}
return proto;
}
auto jbooleans = Java_AssistantValue_getBooleans(env, jvalue);
if (jbooleans) {
auto* mutable_booleans = proto.mutable_booleans();
std::vector<bool> booleans;
base::android::JavaBooleanArrayToBoolVector(env, jbooleans, &booleans);
for (auto b : booleans) {
mutable_booleans->add_values(b);
}
return proto;
}
auto jstrings = Java_AssistantValue_getStrings(env, jvalue);
if (jstrings) {
auto* mutable_strings = proto.mutable_strings();
std::vector<std::string> strings;
base::android::AppendJavaStringArrayToStringVector(env, jstrings, &strings);
for (const auto& string : strings) {
mutable_strings->add_values(string);
}
return proto;
}
auto jdatetimes = Java_AssistantValue_getDateTimes(env, jvalue);
if (jdatetimes) {
auto* mutable_dates = proto.mutable_dates();
for (int i = 0; i < Java_AssistantValue_getListSize(env, jdatetimes); ++i) {
auto jvalue = Java_AssistantValue_getListAt(env, jdatetimes, i);
DateProto date;
date.set_year(Java_AssistantDateTime_getYear(env, jvalue));
date.set_month(Java_AssistantDateTime_getMonth(env, jvalue));
date.set_day(Java_AssistantDateTime_getDay(env, jvalue));
*mutable_dates->add_values() = date;
}
return proto;
}
return proto;
}
base::android::ScopedJavaLocalRef<jobject> CreateJavaDialogButton(
JNIEnv* env,
const InfoPopupProto_DialogButton& button_proto) {
base::android::ScopedJavaLocalRef<jstring> jurl = nullptr;
switch (button_proto.click_action_case()) {
case InfoPopupProto::DialogButton::kOpenUrlInCct:
jurl = base::android::ConvertUTF8ToJavaString(
env, button_proto.open_url_in_cct().url());
break;
case InfoPopupProto::DialogButton::kCloseDialog:
break;
case InfoPopupProto::DialogButton::CLICK_ACTION_NOT_SET:
NOTREACHED();
break;
}
return Java_AssistantDialogButton_Constructor(
env, base::android::ConvertUTF8ToJavaString(env, button_proto.label()),
jurl);
}
base::android::ScopedJavaLocalRef<jobject> CreateJavaInfoPopup(
JNIEnv* env,
const InfoPopupProto& info_popup_proto) {
base::android::ScopedJavaLocalRef<jobject> jpositive_button = nullptr;
base::android::ScopedJavaLocalRef<jobject> jnegative_button = nullptr;
base::android::ScopedJavaLocalRef<jobject> jneutral_button = nullptr;
if (info_popup_proto.has_positive_button() ||
info_popup_proto.has_negative_button() ||
info_popup_proto.has_neutral_button()) {
if (info_popup_proto.has_positive_button()) {
jpositive_button =
CreateJavaDialogButton(env, info_popup_proto.positive_button());
}
if (info_popup_proto.has_negative_button()) {
jnegative_button =
CreateJavaDialogButton(env, info_popup_proto.negative_button());
}
if (info_popup_proto.has_neutral_button()) {
jneutral_button =
CreateJavaDialogButton(env, info_popup_proto.neutral_button());
}
} else {
// If no button is set in the proto, we add a Close button
jpositive_button = Java_AssistantDialogButton_Constructor(
env,
base::android::ConvertUTF8ToJavaString(
env, l10n_util::GetStringUTF8(IDS_CLOSE)),
nullptr);
}
return Java_AssistantInfoPopup_Constructor(
env,
base::android::ConvertUTF8ToJavaString(env, info_popup_proto.title()),
base::android::ConvertUTF8ToJavaString(env, info_popup_proto.text()),
jpositive_button, jnegative_button, jneutral_button);
}
void ShowJavaInfoPopup(JNIEnv* env,
base::android::ScopedJavaLocalRef<jobject> jinfo_popup,
base::android::ScopedJavaLocalRef<jobject> jcontext) {
Java_AssistantInfoPopup_show(env, jinfo_popup, jcontext);
}
std::string SafeConvertJavaStringToNative(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jstring) {
std::string native_string;
if (jstring) {
base::android::ConvertJavaStringToUTF8(env, jstring, &native_string);
}
return native_string;
}
} // namespace ui_controller_android_utils
} // namespace autofill_assistant