Commit ec32558d authored by Clemens Arbesser's avatar Clemens Arbesser Committed by Commit Bot

[Autofill Assistant] Add support for InfoPopups to generic UI.

Bug: b/145043394
Change-Id: I37d416be30ccbf46d990548566f3d2521c7baeef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2033152Reviewed-by: default avatarMathias Carlen <mcarlen@chromium.org>
Commit-Queue: Clemens Arbesser <arbesser@google.com>
Cr-Commit-Position: refs/heads/master@{#737735}
parent a84cd534
......@@ -46,6 +46,7 @@ public class AssistantInfoPopup {
return mText;
}
@CalledByNative
public void show(Context context) {
AlertDialog.Builder builder = new UiUtils
.CompatibleAlertDialogBuilder(context,
......
......@@ -215,8 +215,8 @@ GenericUiControllerAndroid::~GenericUiControllerAndroid() {
std::unique_ptr<GenericUiControllerAndroid>
GenericUiControllerAndroid::CreateFromProto(
const GenericUserInterfaceProto& proto,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const base::android::ScopedJavaGlobalRef<jobject>& jdelegate,
base::android::ScopedJavaLocalRef<jobject> jcontext,
base::android::ScopedJavaGlobalRef<jobject> jdelegate,
UserModel* user_model,
EventHandler* event_handler) {
// Create view layout.
......@@ -231,7 +231,7 @@ GenericUiControllerAndroid::CreateFromProto(
// Create interactions.
auto interaction_handler =
std::make_unique<InteractionHandlerAndroid>(event_handler);
std::make_unique<InteractionHandlerAndroid>(event_handler, jcontext);
if (!interaction_handler->AddInteractionsFromProto(
proto.interactions(), env, *views, jdelegate, user_model)) {
return nullptr;
......
......@@ -22,11 +22,12 @@ class UserModel;
class GenericUiControllerAndroid {
public:
// Attempts to creata a new instance. May fail if the proto is invalid.
// |delegate|, |user_model| and |event_handler| must outlive this instance.
// |jcontext|, |delegate|, |user_model| and |event_handler| must outlive this
// instance. Ownership of the arguments is not changed.
static std::unique_ptr<GenericUiControllerAndroid> CreateFromProto(
const GenericUserInterfaceProto& proto,
const base::android::ScopedJavaLocalRef<jobject>& jcontext,
const base::android::ScopedJavaGlobalRef<jobject>& delegate,
base::android::ScopedJavaLocalRef<jobject> jcontext,
base::android::ScopedJavaGlobalRef<jobject> delegate,
UserModel* user_model,
EventHandler* event_handler);
......
......@@ -25,6 +25,16 @@ void SetValue(base::WeakPtr<UserModel> user_model,
user_model->SetValue(identifier, value);
}
void ShowInfoPopup(const InfoPopupProto& proto,
base::android::ScopedJavaGlobalRef<jobject> jcontext,
const ValueProto& ignored) {
JNIEnv* env = base::android::AttachCurrentThread();
auto jcontext_local = base::android::ScopedJavaLocalRef<jobject>(jcontext);
ui_controller_android_utils::ShowJavaInfoPopup(
env, ui_controller_android_utils::CreateJavaInfoPopup(env, proto),
jcontext_local);
}
base::Optional<EventHandler::EventKey> CreateEventKeyFromProto(
const EventProto& proto,
JNIEnv* env,
......@@ -60,8 +70,10 @@ base::Optional<EventHandler::EventKey> CreateEventKeyFromProto(
}
base::Optional<InteractionHandlerAndroid::InteractionCallback>
CreateInteractionCallbackFromProto(const CallbackProto& proto,
UserModel* user_model) {
CreateInteractionCallbackFromProto(
const CallbackProto& proto,
UserModel* user_model,
base::android::ScopedJavaGlobalRef<jobject> jcontext) {
switch (proto.kind_case()) {
case CallbackProto::kSetValue:
if (proto.set_value().model_identifier().empty()) {
......@@ -72,6 +84,11 @@ CreateInteractionCallbackFromProto(const CallbackProto& proto,
return base::Optional<InteractionHandlerAndroid::InteractionCallback>(
base::BindRepeating(&SetValue, user_model->GetWeakPtr(),
proto.set_value().model_identifier()));
case CallbackProto::kShowInfoPopup: {
return base::Optional<InteractionHandlerAndroid::InteractionCallback>(
base::BindRepeating(&ShowInfoPopup,
proto.show_info_popup().info_popup(), jcontext));
}
case CallbackProto::KIND_NOT_SET:
VLOG(1) << "Error creating interaction: kind not set";
return base::nullopt;
......@@ -81,8 +98,13 @@ CreateInteractionCallbackFromProto(const CallbackProto& proto,
} // namespace
InteractionHandlerAndroid::InteractionHandlerAndroid(
EventHandler* event_handler)
: event_handler_(event_handler) {}
EventHandler* event_handler,
base::android::ScopedJavaLocalRef<jobject> jcontext)
: event_handler_(event_handler) {
DCHECK(jcontext);
jcontext_ = base::android::ScopedJavaGlobalRef<jobject>(jcontext);
}
InteractionHandlerAndroid::~InteractionHandlerAndroid() {
event_handler_->RemoveObserver(this);
}
......@@ -117,8 +139,8 @@ bool InteractionHandlerAndroid::AddInteractionsFromProto(
}
for (const auto& callback_proto : interaction_proto.callbacks()) {
auto callback =
CreateInteractionCallbackFromProto(callback_proto, user_model);
auto callback = CreateInteractionCallbackFromProto(callback_proto,
user_model, jcontext_);
if (!callback) {
VLOG(1) << "Invalid callback for interaction";
return false;
......
......@@ -31,8 +31,10 @@ class InteractionHandlerAndroid : public EventHandler::Observer {
// Each interaction callback has exactly one free |ValueProto| parameter.
using InteractionCallback = base::RepeatingCallback<void(const ValueProto&)>;
// Constructor. |event_handler| must outlive this instance.
explicit InteractionHandlerAndroid(EventHandler* event_handler);
// Constructor. |event_handler| and |jcontext| must outlive this instance.
InteractionHandlerAndroid(
EventHandler* event_handler,
base::android::ScopedJavaLocalRef<jobject> jcontext);
~InteractionHandlerAndroid() override;
void StartListening();
......@@ -61,6 +63,7 @@ class InteractionHandlerAndroid : public EventHandler::Observer {
interactions_;
EventHandler* event_handler_ = nullptr;
base::android::ScopedJavaGlobalRef<jobject> jcontext_ = nullptr;
bool is_listening_ = false;
DISALLOW_COPY_AND_ASSIGN(InteractionHandlerAndroid);
};
......
......@@ -20,13 +20,11 @@
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantCollectUserDataModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDetailsModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDetails_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantDialogButton_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantFormInput_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantFormModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantHeaderModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantInfoBoxModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantInfoBox_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantInfoPopup_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantOverlayModel_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AutofillAssistantUiController_jni.h"
......@@ -94,65 +92,6 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaDate(
return CreateJavaDateTime(env, date_time);
}
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);
}
// Creates the Java equivalent to |login_choices|.
base::android::ScopedJavaLocalRef<jobject> CreateJavaLoginChoiceList(
JNIEnv* env,
......@@ -161,7 +100,8 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaLoginChoiceList(
for (const auto& login_choice : login_choices) {
base::android::ScopedJavaLocalRef<jobject> jinfo_popup = nullptr;
if (login_choice.info_popup.has_value()) {
jinfo_popup = CreateJavaInfoPopup(env, *login_choice.info_popup);
jinfo_popup = ui_controller_android_utils::CreateJavaInfoPopup(
env, *login_choice.info_popup);
}
base::android::ScopedJavaLocalRef<jstring> jsublabel_accessibility_hint =
nullptr;
......@@ -1430,7 +1370,9 @@ void UiControllerAndroid::OnFormChanged(const FormProto* form) {
if (form->has_info_popup()) {
Java_AssistantFormModel_setInfoPopup(
env, GetFormModel(), CreateJavaInfoPopup(env, form->info_popup()));
env, GetFormModel(),
ui_controller_android_utils::CreateJavaInfoPopup(env,
form->info_popup()));
} else {
Java_AssistantFormModel_clearInfoPopup(env, GetFormModel());
}
......
......@@ -6,8 +6,12 @@
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantColor_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/AssistantInfoPopup_jni.h"
#include "chrome/android/features/autofill_assistant/jni_headers/AssistantValue_jni.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill_assistant {
......@@ -161,6 +165,71 @@ ValueProto ToNativeValue(JNIEnv* env,
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);
}
} // namespace ui_controller_android_utils
} // namespace autofill_assistant
......@@ -12,6 +12,7 @@
#include "base/android/jni_android.h"
#include "base/optional.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/view_layout.pb.h"
namespace autofill_assistant {
......@@ -54,6 +55,16 @@ base::android::ScopedJavaLocalRef<jobject> ToJavaValue(JNIEnv* env,
ValueProto ToNativeValue(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jvalue);
// Returns an instance of |AssistantInfoPopup| for |proto|.
base::android::ScopedJavaLocalRef<jobject> CreateJavaInfoPopup(
JNIEnv* env,
const InfoPopupProto& proto);
// Shows an instance of |AssistantInfoPopup| on the screen.
void ShowJavaInfoPopup(JNIEnv* env,
base::android::ScopedJavaLocalRef<jobject> jinfo_popup,
base::android::ScopedJavaLocalRef<jobject> jcontext);
} // namespace ui_controller_android_utils
} // namespace autofill_assistant
......
......@@ -11,6 +11,7 @@ option java_multiple_files = true;
package autofill_assistant;
import "model.proto";
import "view_layout.proto";
message InteractionsProto {
repeated InteractionProto interactions = 1;
......@@ -26,7 +27,10 @@ message InteractionProto {
// Each callback takes a single |ValueProto| as input. Some callbacks only
// support values of particular types.
message CallbackProto {
oneof kind { SetModelValueCallbackProto set_value = 1; }
oneof kind {
SetModelValueProto set_value = 1;
ShowInfoPopupProto show_info_popup = 2;
}
}
message EventProto {
......@@ -51,11 +55,16 @@ message OnViewClickedEventProto {
}
// Callback that writes the incoming value to |model_identifier|.
message SetModelValueCallbackProto {
message SetModelValueProto {
// The identifier of the value to change.
optional string model_identifier = 1;
}
// Displays a standard info popup.
message ShowInfoPopupProto {
optional InfoPopupProto info_popup = 1;
}
// Callback that expects a boolean input value and enables/disables the
// specified view.
message SetViewEnabledCallbackProto {
......
......@@ -1291,34 +1291,6 @@ message ContactDetailsProto {
optional int32 max_number_full_lines = 8;
}
// A generic read-only popup message.
message InfoPopupProto {
// The title of the popup window.
optional string title = 1;
// The text of the popup window.
optional string text = 2;
message DialogButton {
message CloseDialog {}
message OpenUrlInCCT { optional string url = 1; }
// The action to be executed on click.
oneof click_action {
// Closes the popup.
CloseDialog close_dialog = 4;
// Opens the specified url into a new CCT.
OpenUrlInCCT open_url_in_cct = 5;
}
optional string label = 1;
}
// Optional: adds a positive button.
optional DialogButton positive_button = 3;
// Optional: adds a negative button.
optional DialogButton negative_button = 4;
// Optional: adds a neutral button.
optional DialogButton neutral_button = 5;
}
message LoginDetailsProto {
// A custom login option which will be handled by the backend, e.g.,
// 'Guest checkout' or 'Log in with Google'.
......
......@@ -156,4 +156,32 @@ message ImageViewProto {
optional DrawableProto image = 1;
}
message CheckBoxViewProto {}
\ No newline at end of file
message CheckBoxViewProto {}
// A generic read-only popup message.
message InfoPopupProto {
// The title of the popup window.
optional string title = 1;
// The text of the popup window.
optional string text = 2;
message DialogButton {
message CloseDialog {}
message OpenUrlInCCT { optional string url = 1; }
// The action to be executed on click.
oneof click_action {
// Closes the popup.
CloseDialog close_dialog = 4;
// Opens the specified url into a new CCT.
OpenUrlInCCT open_url_in_cct = 5;
}
optional string label = 1;
}
// Optional: adds a positive button.
optional DialogButton positive_button = 3;
// Optional: adds a negative button.
optional DialogButton negative_button = 4;
// Optional: adds a neutral button.
optional DialogButton neutral_button = 5;
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment