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

[Autofill Assistant] Added second container for generic UI.

This CL adds a second container for generic UI to the CollectUserData
action. The first container is right after prepended_sections (no
change), the new second container is after appended_sections.

Conceptually, this will allow the specification of additional sections,
both prepended and appended ones, in either the dedicated proto or via
generic UI.

In the mid-term, I plan to remove those legacy additional sections
completely, but for now, the two will co-exist.

Bug: b/145043394
Change-Id: Iaabfa5fd7d3b71b287e9b0458fcd0790553ee490
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2030488
Commit-Queue: Clemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarMathias Carlen <mcarlen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737313}
parent 68c01000
...@@ -60,7 +60,8 @@ class AssistantCollectUserDataBinder ...@@ -60,7 +60,8 @@ class AssistantCollectUserDataBinder
private final AssistantInfoSection mInfoSection; private final AssistantInfoSection mInfoSection;
private final AssistantAdditionalSectionContainer mPrependedSections; private final AssistantAdditionalSectionContainer mPrependedSections;
private final AssistantAdditionalSectionContainer mAppendedSections; private final AssistantAdditionalSectionContainer mAppendedSections;
private final ViewGroup mGenericUserInterfaceContainer; private final ViewGroup mGenericUserInterfaceContainerPrepended;
private final ViewGroup mGenericUserInterfaceContainerAppended;
private final Object mDividerTag; private final Object mDividerTag;
private final Activity mActivity; private final Activity mActivity;
...@@ -75,7 +76,9 @@ class AssistantCollectUserDataBinder ...@@ -75,7 +76,9 @@ class AssistantCollectUserDataBinder
AssistantInfoSection infoSection, AssistantInfoSection infoSection,
AssistantAdditionalSectionContainer prependedSections, AssistantAdditionalSectionContainer prependedSections,
AssistantAdditionalSectionContainer appendedSections, AssistantAdditionalSectionContainer appendedSections,
ViewGroup genericUserInterfaceContainer, Object dividerTag, Activity activity) { ViewGroup genericUserInterfaceContainerPrepended,
ViewGroup genericUserInterfaceContainerAppended, Object dividerTag,
Activity activity) {
mRootView = rootView; mRootView = rootView;
mPaymentRequestExpanderAccordion = accordion; mPaymentRequestExpanderAccordion = accordion;
mSectionToSectionPadding = sectionPadding; mSectionToSectionPadding = sectionPadding;
...@@ -90,7 +93,8 @@ class AssistantCollectUserDataBinder ...@@ -90,7 +93,8 @@ class AssistantCollectUserDataBinder
mInfoSection = infoSection; mInfoSection = infoSection;
mPrependedSections = prependedSections; mPrependedSections = prependedSections;
mAppendedSections = appendedSections; mAppendedSections = appendedSections;
mGenericUserInterfaceContainer = genericUserInterfaceContainer; mGenericUserInterfaceContainerPrepended = genericUserInterfaceContainerPrepended;
mGenericUserInterfaceContainerAppended = genericUserInterfaceContainerAppended;
mDividerTag = dividerTag; mDividerTag = dividerTag;
mActivity = activity; mActivity = activity;
} }
...@@ -357,11 +361,18 @@ class AssistantCollectUserDataBinder ...@@ -357,11 +361,18 @@ class AssistantCollectUserDataBinder
view.mTermsAsCheckboxSection.setPrivacyNoticeText( view.mTermsAsCheckboxSection.setPrivacyNoticeText(
model.get(AssistantCollectUserDataModel.PRIVACY_NOTICE_TEXT)); model.get(AssistantCollectUserDataModel.PRIVACY_NOTICE_TEXT));
return true; return true;
} else if (propertyKey == AssistantCollectUserDataModel.GENERIC_USER_INTERFACE) { } else if (propertyKey == AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_PREPENDED) {
view.mGenericUserInterfaceContainer.removeAllViews(); view.mGenericUserInterfaceContainerPrepended.removeAllViews();
if (model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE) != null) { if (model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_PREPENDED) != null) {
view.mGenericUserInterfaceContainer.addView( view.mGenericUserInterfaceContainerPrepended.addView(
model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE)); model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_PREPENDED));
}
return true;
} else if (propertyKey == AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_APPENDED) {
view.mGenericUserInterfaceContainerAppended.removeAllViews();
if (model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_APPENDED) != null) {
view.mGenericUserInterfaceContainerAppended.addView(
model.get(AssistantCollectUserDataModel.GENERIC_USER_INTERFACE_APPENDED));
} }
return true; return true;
} else if (propertyKey } else if (propertyKey
......
...@@ -76,9 +76,9 @@ public class AssistantCollectUserDataCoordinator { ...@@ -76,9 +76,9 @@ public class AssistantCollectUserDataCoordinator {
AssistantAdditionalSectionContainer prependedSections = AssistantAdditionalSectionContainer prependedSections =
new AssistantAdditionalSectionContainer(mActivity, paymentRequestExpanderAccordion); new AssistantAdditionalSectionContainer(mActivity, paymentRequestExpanderAccordion);
LinearLayout genericUserInterfaceContainer = new LinearLayout(activity); LinearLayout genericUserInterfaceContainerPrepended = new LinearLayout(activity);
genericUserInterfaceContainer.setOrientation(LinearLayout.VERTICAL); genericUserInterfaceContainerPrepended.setOrientation(LinearLayout.VERTICAL);
paymentRequestExpanderAccordion.addView(genericUserInterfaceContainer, paymentRequestExpanderAccordion.addView(genericUserInterfaceContainerPrepended,
new LinearLayout.LayoutParams( new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
...@@ -106,6 +106,12 @@ public class AssistantCollectUserDataCoordinator { ...@@ -106,6 +106,12 @@ public class AssistantCollectUserDataCoordinator {
AssistantAdditionalSectionContainer appendedSections = AssistantAdditionalSectionContainer appendedSections =
new AssistantAdditionalSectionContainer(mActivity, paymentRequestExpanderAccordion); new AssistantAdditionalSectionContainer(mActivity, paymentRequestExpanderAccordion);
LinearLayout genericUserInterfaceContainerAppended = new LinearLayout(activity);
genericUserInterfaceContainerAppended.setOrientation(LinearLayout.VERTICAL);
paymentRequestExpanderAccordion.addView(genericUserInterfaceContainerAppended,
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
AssistantTermsSection termsSection = new AssistantTermsSection( AssistantTermsSection termsSection = new AssistantTermsSection(
mActivity, paymentRequestExpanderAccordion, /* showAsSingleCheckbox= */ false); mActivity, paymentRequestExpanderAccordion, /* showAsSingleCheckbox= */ false);
AssistantTermsSection termsAsCheckboxSection = AssistantTermsSection termsAsCheckboxSection =
...@@ -139,7 +145,8 @@ public class AssistantCollectUserDataCoordinator { ...@@ -139,7 +145,8 @@ public class AssistantCollectUserDataCoordinator {
paymentRequestExpanderAccordion, sectionToSectionPadding, loginSection, paymentRequestExpanderAccordion, sectionToSectionPadding, loginSection,
contactDetailsSection, dateRangeStartSection, dateRangeEndSection, contactDetailsSection, dateRangeStartSection, dateRangeEndSection,
paymentMethodSection, shippingAddressSection, termsSection, termsAsCheckboxSection, paymentMethodSection, shippingAddressSection, termsSection, termsAsCheckboxSection,
infoSection, prependedSections, appendedSections, genericUserInterfaceContainer, infoSection, prependedSections, appendedSections,
genericUserInterfaceContainerPrepended, genericUserInterfaceContainerAppended,
DIVIDER_TAG, activity); DIVIDER_TAG, activity);
AssistantCollectUserDataBinder binder = new AssistantCollectUserDataBinder(); AssistantCollectUserDataBinder binder = new AssistantCollectUserDataBinder();
PropertyModelChangeProcessor.create(model, mViewHolder, binder); PropertyModelChangeProcessor.create(model, mViewHolder, binder);
......
...@@ -176,7 +176,10 @@ public class AssistantCollectUserDataModel extends PropertyModel { ...@@ -176,7 +176,10 @@ public class AssistantCollectUserDataModel extends PropertyModel {
public static final WritableObjectPropertyKey<String> INFO_SECTION_TEXT = public static final WritableObjectPropertyKey<String> INFO_SECTION_TEXT =
new WritableObjectPropertyKey<>(); new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<View> GENERIC_USER_INTERFACE = public static final WritableObjectPropertyKey<View> GENERIC_USER_INTERFACE_PREPENDED =
new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<View> GENERIC_USER_INTERFACE_APPENDED =
new WritableObjectPropertyKey<>(); new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<ContactDescriptionOptions> public static final WritableObjectPropertyKey<ContactDescriptionOptions>
...@@ -200,8 +203,9 @@ public class AssistantCollectUserDataModel extends PropertyModel { ...@@ -200,8 +203,9 @@ public class AssistantCollectUserDataModel extends PropertyModel {
DATE_RANGE_END_TIMESLOT, DATE_RANGE_END_DATE_LABEL, DATE_RANGE_END_TIME_LABEL, DATE_RANGE_END_TIMESLOT, DATE_RANGE_END_DATE_LABEL, DATE_RANGE_END_TIME_LABEL,
DATE_RANGE_DATE_NOT_SET_ERROR_MESSAGE, DATE_RANGE_TIME_NOT_SET_ERROR_MESSAGE, DATE_RANGE_DATE_NOT_SET_ERROR_MESSAGE, DATE_RANGE_TIME_NOT_SET_ERROR_MESSAGE,
PREPENDED_SECTIONS, APPENDED_SECTIONS, TERMS_REQUIRE_REVIEW_TEXT, PREPENDED_SECTIONS, APPENDED_SECTIONS, TERMS_REQUIRE_REVIEW_TEXT,
PRIVACY_NOTICE_TEXT, INFO_SECTION_TEXT, GENERIC_USER_INTERFACE, PRIVACY_NOTICE_TEXT, INFO_SECTION_TEXT, GENERIC_USER_INTERFACE_PREPENDED,
CONTACT_SUMMARY_DESCRIPTION_OPTIONS, CONTACT_FULL_DESCRIPTION_OPTIONS); GENERIC_USER_INTERFACE_APPENDED, CONTACT_SUMMARY_DESCRIPTION_OPTIONS,
CONTACT_FULL_DESCRIPTION_OPTIONS);
/** /**
* Set initial state for basic type properties (others are implicitly null). * Set initial state for basic type properties (others are implicitly null).
...@@ -611,8 +615,13 @@ public class AssistantCollectUserDataModel extends PropertyModel { ...@@ -611,8 +615,13 @@ public class AssistantCollectUserDataModel extends PropertyModel {
} }
@CalledByNative @CalledByNative
private void setGenericUserInterface(@Nullable View userInterface) { private void setGenericUserInterfacePrepended(@Nullable View userInterface) {
set(GENERIC_USER_INTERFACE, userInterface); set(GENERIC_USER_INTERFACE_PREPENDED, userInterface);
}
@CalledByNative
private void setGenericUserInterfaceAppended(@Nullable View userInterface) {
set(GENERIC_USER_INTERFACE_APPENDED, userInterface);
} }
@CalledByNative @CalledByNative
......
...@@ -214,7 +214,7 @@ public class AutofillAssistantGenericUiTest { ...@@ -214,7 +214,7 @@ public class AutofillAssistantGenericUiTest {
list.add((ActionProto) ActionProto.newBuilder() list.add((ActionProto) ActionProto.newBuilder()
.setCollectUserData( .setCollectUserData(
CollectUserDataProto.newBuilder() CollectUserDataProto.newBuilder()
.setGenericUserInterface( .setGenericUserInterfacePrepended(
GenericUserInterfaceProto.newBuilder().setRootView( GenericUserInterfaceProto.newBuilder().setRootView(
rootView)) rootView))
.setPrivacyNoticeText( .setPrivacyNoticeText(
...@@ -266,19 +266,27 @@ public class AutofillAssistantGenericUiTest { ...@@ -266,19 +266,27 @@ public class AutofillAssistantGenericUiTest {
.setIdentifier("clickableView2") .setIdentifier("clickableView2")
.build(); .build();
ViewProto rootView = ViewProto rootViewPrepended =
(ViewProto) ViewProto.newBuilder()
.setViewContainer(
ViewContainerProto.newBuilder()
.setLinearLayout(
LinearLayoutProto.newBuilder().setOrientation(
LinearLayoutProto.Orientation.VERTICAL))
.addViews(clickableView1))
.build();
ViewProto rootViewAppended =
(ViewProto) ViewProto.newBuilder() (ViewProto) ViewProto.newBuilder()
.setViewContainer( .setViewContainer(
ViewContainerProto.newBuilder() ViewContainerProto.newBuilder()
.setLinearLayout( .setLinearLayout(
LinearLayoutProto.newBuilder().setOrientation( LinearLayoutProto.newBuilder().setOrientation(
LinearLayoutProto.Orientation.VERTICAL)) LinearLayoutProto.Orientation.VERTICAL))
.addViews(clickableView1)
.addViews(clickableView2)) .addViews(clickableView2))
.build(); .build();
List<InteractionProto> interactions = new ArrayList<>(); List<InteractionProto> interactionsPrepended = new ArrayList<>();
interactions.add( interactionsPrepended.add(
(InteractionProto) InteractionProto.newBuilder() (InteractionProto) InteractionProto.newBuilder()
.setTriggerEvent(EventProto.newBuilder().setOnViewClicked( .setTriggerEvent(EventProto.newBuilder().setOnViewClicked(
OnViewClickedEventProto.newBuilder() OnViewClickedEventProto.newBuilder()
...@@ -289,7 +297,8 @@ public class AutofillAssistantGenericUiTest { ...@@ -289,7 +297,8 @@ public class AutofillAssistantGenericUiTest {
SetModelValueCallbackProto.newBuilder().setModelIdentifier( SetModelValueCallbackProto.newBuilder().setModelIdentifier(
"output_1"))) "output_1")))
.build()); .build());
interactions.add( List<InteractionProto> interactionsAppended = new ArrayList<>();
interactionsAppended.add(
(InteractionProto) InteractionProto.newBuilder() (InteractionProto) InteractionProto.newBuilder()
.setTriggerEvent(EventProto.newBuilder().setOnViewClicked( .setTriggerEvent(EventProto.newBuilder().setOnViewClicked(
OnViewClickedEventProto.newBuilder() OnViewClickedEventProto.newBuilder()
...@@ -301,28 +310,39 @@ public class AutofillAssistantGenericUiTest { ...@@ -301,28 +310,39 @@ public class AutofillAssistantGenericUiTest {
"output_2"))) "output_2")))
.build()); .build());
List<ModelProto.ModelValue> modelValues = new ArrayList<>(); List<ModelProto.ModelValue> modelValuesPrepended = new ArrayList<>();
modelValues.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() modelValuesPrepended.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder()
.setIdentifier("output_1") .setIdentifier("output_1")
.build()); .build());
modelValues.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder() List<ModelProto.ModelValue> modelValuesAppended = new ArrayList<>();
.setIdentifier("output_2") modelValuesAppended.add((ModelProto.ModelValue) ModelProto.ModelValue.newBuilder()
.build()); .setIdentifier("output_2")
.build());
GenericUserInterfaceProto genericUserInterfacePrepended =
(GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder()
.setRootView(rootViewPrepended)
.setInteractions(InteractionsProto.newBuilder().addAllInteractions(
interactionsPrepended))
.setModel(ModelProto.newBuilder().addAllValues(modelValuesPrepended))
.build();
GenericUserInterfaceProto genericUserInterfaceAppended =
(GenericUserInterfaceProto) GenericUserInterfaceProto.newBuilder()
.setRootView(rootViewAppended)
.setInteractions(InteractionsProto.newBuilder().addAllInteractions(
interactionsAppended))
.setModel(ModelProto.newBuilder().addAllValues(modelValuesAppended))
.build();
ArrayList<ActionProto> list = new ArrayList<>(); ArrayList<ActionProto> list = new ArrayList<>();
list.add((ActionProto) ActionProto.newBuilder() list.add((ActionProto) ActionProto.newBuilder()
.setCollectUserData( .setCollectUserData(
CollectUserDataProto.newBuilder() CollectUserDataProto.newBuilder()
.setGenericUserInterface( .setGenericUserInterfacePrepended(
GenericUserInterfaceProto.newBuilder() genericUserInterfacePrepended)
.setRootView(rootView) .setGenericUserInterfaceAppended(
.setInteractions( genericUserInterfaceAppended)
InteractionsProto.newBuilder()
.addAllInteractions(
interactions))
.setModel(ModelProto.newBuilder()
.addAllValues(
modelValues)))
.setPrivacyNoticeText( .setPrivacyNoticeText(
"Chrome will send selected data to example.com") "Chrome will send selected data to example.com")
.setRequestTermsAndConditions(false)) .setRequestTermsAndConditions(false))
...@@ -454,7 +474,7 @@ public class AutofillAssistantGenericUiTest { ...@@ -454,7 +474,7 @@ public class AutofillAssistantGenericUiTest {
list.add((ActionProto) ActionProto.newBuilder() list.add((ActionProto) ActionProto.newBuilder()
.setCollectUserData( .setCollectUserData(
CollectUserDataProto.newBuilder() CollectUserDataProto.newBuilder()
.setGenericUserInterface( .setGenericUserInterfacePrepended(
GenericUserInterfaceProto.newBuilder() GenericUserInterfaceProto.newBuilder()
.setRootView(rootView) .setRootView(rootView)
.setInteractions( .setInteractions(
......
...@@ -851,7 +851,7 @@ void UiControllerAndroid::Detach() { ...@@ -851,7 +851,7 @@ void UiControllerAndroid::Detach() {
if (!ui_delegate_) if (!ui_delegate_)
return; return;
collect_user_data_generic_ui_controller_.reset(); ResetGenericUiControllers();
// Capture the debug context, for including into a feedback possibly sent // Capture the debug context, for including into a feedback possibly sent
// later. // later.
...@@ -970,9 +970,7 @@ void UiControllerAndroid::OnCollectUserDataOptionsChanged( ...@@ -970,9 +970,7 @@ void UiControllerAndroid::OnCollectUserDataOptionsChanged(
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
auto jmodel = GetCollectUserDataModel(); auto jmodel = GetCollectUserDataModel();
if (!collect_user_data_options) { if (!collect_user_data_options) {
collect_user_data_generic_ui_controller_.reset(); ResetGenericUiControllers();
Java_AssistantCollectUserDataModel_setGenericUserInterface(env, jmodel,
nullptr);
Java_AssistantCollectUserDataModel_setVisible(env, jmodel, false); Java_AssistantCollectUserDataModel_setVisible(env, jmodel, false);
return; return;
} }
...@@ -1103,18 +1101,25 @@ void UiControllerAndroid::OnCollectUserDataOptionsChanged( ...@@ -1103,18 +1101,25 @@ void UiControllerAndroid::OnCollectUserDataOptionsChanged(
env, jmodel, env, jmodel,
CreateJavaAdditionalSections( CreateJavaAdditionalSections(
env, collect_user_data_options->additional_appended_sections)); env, collect_user_data_options->additional_appended_sections));
if (collect_user_data_options->generic_user_interface.has_value()) {
auto jcontext = if (collect_user_data_options->generic_user_interface_prepended.has_value()) {
Java_AutofillAssistantUiController_getContext(env, java_object_); collect_user_data_prepended_generic_ui_controller_ =
collect_user_data_generic_ui_controller_ = CreateGenericUiControllerForProto(
GenericUiControllerAndroid::CreateFromProto( *collect_user_data_options->generic_user_interface_prepended);
*collect_user_data_options->generic_user_interface, jcontext, Java_AssistantCollectUserDataModel_setGenericUserInterfacePrepended(
generic_ui_delegate_.GetJavaObject(), ui_delegate_->GetUserModel(), env, jmodel,
ui_delegate_->GetEventHandler()); collect_user_data_prepended_generic_ui_controller_ != nullptr
Java_AssistantCollectUserDataModel_setGenericUserInterface( ? collect_user_data_prepended_generic_ui_controller_->GetRootView()
: nullptr);
}
if (collect_user_data_options->generic_user_interface_appended.has_value()) {
collect_user_data_appended_generic_ui_controller_ =
CreateGenericUiControllerForProto(
*collect_user_data_options->generic_user_interface_appended);
Java_AssistantCollectUserDataModel_setGenericUserInterfaceAppended(
env, jmodel, env, jmodel,
collect_user_data_generic_ui_controller_ != nullptr collect_user_data_appended_generic_ui_controller_ != nullptr
? collect_user_data_generic_ui_controller_->GetRootView() ? collect_user_data_appended_generic_ui_controller_->GetRootView()
: nullptr); : nullptr);
} }
...@@ -1562,4 +1567,27 @@ void UiControllerAndroid::OnFatalError( ...@@ -1562,4 +1567,27 @@ void UiControllerAndroid::OnFatalError(
base::android::ConvertJavaStringToUTF8(env, jmessage), base::android::ConvertJavaStringToUTF8(env, jmessage),
static_cast<Metrics::DropOutReason>(jreason)); static_cast<Metrics::DropOutReason>(jreason));
} }
void UiControllerAndroid::ResetGenericUiControllers() {
JNIEnv* env = AttachCurrentThread();
auto jmodel = GetCollectUserDataModel();
collect_user_data_prepended_generic_ui_controller_.reset();
collect_user_data_appended_generic_ui_controller_.reset();
Java_AssistantCollectUserDataModel_setGenericUserInterfacePrepended(
env, jmodel, nullptr);
Java_AssistantCollectUserDataModel_setGenericUserInterfaceAppended(
env, jmodel, nullptr);
}
std::unique_ptr<GenericUiControllerAndroid>
UiControllerAndroid::CreateGenericUiControllerForProto(
const GenericUserInterfaceProto& proto) {
JNIEnv* env = AttachCurrentThread();
auto jcontext =
Java_AutofillAssistantUiController_getContext(env, java_object_);
return GenericUiControllerAndroid::CreateFromProto(
proto, jcontext, generic_ui_delegate_.GetJavaObject(),
ui_delegate_->GetUserModel(), ui_delegate_->GetEventHandler());
}
} // namespace autofill_assistant } // namespace autofill_assistant
...@@ -210,6 +210,10 @@ class UiControllerAndroid : public ControllerObserver { ...@@ -210,6 +210,10 @@ class UiControllerAndroid : public ControllerObserver {
void UpdateSuggestions(const std::vector<UserAction>& GetUserActions); void UpdateSuggestions(const std::vector<UserAction>& GetUserActions);
void HideKeyboardIfFocusNotOnText(); void HideKeyboardIfFocusNotOnText();
void ResetGenericUiControllers();
std::unique_ptr<GenericUiControllerAndroid> CreateGenericUiControllerForProto(
const GenericUserInterfaceProto& proto);
// Hide the UI, show a snackbar with an undo button, and execute the given // Hide the UI, show a snackbar with an undo button, and execute the given
// action after a short delay unless the user taps the undo button. // action after a short delay unless the user taps the undo button.
void ShowSnackbar(base::TimeDelta delay, void ShowSnackbar(base::TimeDelta delay,
...@@ -235,9 +239,11 @@ class UiControllerAndroid : public ControllerObserver { ...@@ -235,9 +239,11 @@ class UiControllerAndroid : public ControllerObserver {
// Java-side AutofillAssistantUiController object. // Java-side AutofillAssistantUiController object.
base::android::ScopedJavaGlobalRef<jobject> java_object_; base::android::ScopedJavaGlobalRef<jobject> java_object_;
// Native controller for generic UI in collect user data action. // Native controllers for generic UI in collect user data action.
std::unique_ptr<GenericUiControllerAndroid>
collect_user_data_prepended_generic_ui_controller_;
std::unique_ptr<GenericUiControllerAndroid> std::unique_ptr<GenericUiControllerAndroid>
collect_user_data_generic_ui_controller_; collect_user_data_appended_generic_ui_controller_;
OverlayState desired_overlay_state_ = OverlayState::FULL; OverlayState desired_overlay_state_ = OverlayState::FULL;
base::WeakPtrFactory<UiControllerAndroid> weak_ptr_factory_{this}; base::WeakPtrFactory<UiControllerAndroid> weak_ptr_factory_{this};
......
...@@ -269,6 +269,21 @@ bool IsValidUserFormSection( ...@@ -269,6 +269,21 @@ bool IsValidUserFormSection(
return true; return true;
} }
// Merges |model_a| and |model_b| into a new model.
// TODO(arbesser): deal with overlapping keys.
autofill_assistant::ModelProto MergeModelProtos(
const autofill_assistant::ModelProto& model_a,
const autofill_assistant::ModelProto& model_b) {
autofill_assistant::ModelProto model_merged;
for (const auto& value : model_a.values()) {
*model_merged.add_values() = value;
}
for (const auto& value : model_b.values()) {
*model_merged.add_values() = value;
}
return model_merged;
}
} // namespace } // namespace
namespace autofill_assistant { namespace autofill_assistant {
...@@ -573,10 +588,14 @@ void CollectUserDataAction::OnGetUserData( ...@@ -573,10 +588,14 @@ void CollectUserDataAction::OnGetUserData(
user_data->terms_and_conditions_ == user_data->terms_and_conditions_ ==
TermsAndConditionsState::ACCEPTED); TermsAndConditionsState::ACCEPTED);
if (user_model != nullptr && if (user_model != nullptr &&
collect_user_data.has_generic_user_interface()) { (collect_user_data.has_generic_user_interface_prepended() ||
collect_user_data.has_generic_user_interface_appended())) {
// Build the union of both models (this assumes that there are no
// overlapping model keys).
*processed_action_proto_->mutable_collect_user_data_result() *processed_action_proto_->mutable_collect_user_data_result()
->mutable_model() = ->mutable_model() = MergeModelProtos(
collect_user_data.generic_user_interface().model(); collect_user_data.generic_user_interface_prepended().model(),
collect_user_data.generic_user_interface_appended().model());
user_model->UpdateProto( user_model->UpdateProto(
processed_action_proto_->mutable_collect_user_data_result() processed_action_proto_->mutable_collect_user_data_result()
->mutable_model()); ->mutable_model());
...@@ -803,9 +822,13 @@ bool CollectUserDataAction::CreateOptionsFromProto() { ...@@ -803,9 +822,13 @@ bool CollectUserDataAction::CreateOptionsFromProto() {
return false; return false;
} }
if (collect_user_data.has_generic_user_interface()) { if (collect_user_data.has_generic_user_interface_prepended()) {
collect_user_data_options_->generic_user_interface = collect_user_data_options_->generic_user_interface_prepended =
collect_user_data.generic_user_interface(); collect_user_data.generic_user_interface_prepended();
}
if (collect_user_data.has_generic_user_interface_appended()) {
collect_user_data_options_->generic_user_interface_appended =
collect_user_data.generic_user_interface_appended();
} }
// TODO(crbug.com/806868): Maybe we could refactor this to make the confirm // TODO(crbug.com/806868): Maybe we could refactor this to make the confirm
......
...@@ -1668,5 +1668,76 @@ TEST_F(CollectUserDataActionTest, ResetsCardAndAddressIfNoLongerInList) { ...@@ -1668,5 +1668,76 @@ TEST_F(CollectUserDataActionTest, ResetsCardAndAddressIfNoLongerInList) {
action.ProcessAction(callback_.Get()); action.ProcessAction(callback_.Get());
} }
TEST_F(CollectUserDataActionTest, GenericUiModelWritesToProtoResult) {
ModelProto::ModelValue value_1;
value_1.set_identifier("value_1_key");
value_1.mutable_value()->mutable_strings()->add_values(
"value_1_initial_value");
ModelProto::ModelValue value_1_modified;
value_1_modified.set_identifier("value_1_key");
ModelProto::ModelValue value_2;
value_2.set_identifier("value_2_key");
value_2.mutable_value()->mutable_strings()->add_values(
"value_2_initial_value");
ModelProto::ModelValue value_2_modified;
value_2_modified.set_identifier("value_2_key");
value_2_modified.mutable_value()->mutable_strings()->add_values(
"value_2_modified");
ModelProto::ModelValue value_3;
value_3.set_identifier("value_3_key");
value_3.mutable_value()->mutable_strings()->add_values(
"value_3_initial_value");
ModelProto::ModelValue value_3_modified;
value_3_modified.set_identifier("value_3_key");
value_3_modified.mutable_value()->mutable_strings()->add_values(
"value_3_modified");
ModelProto::ModelValue value_4;
value_4.set_identifier("value_4_key");
value_4.mutable_value()->mutable_strings()->add_values(
"value_4_initial_value");
ON_CALL(mock_action_delegate_, CollectUserData(_))
.WillByDefault(
Invoke([=](CollectUserDataOptions* collect_user_data_options) {
user_data_.succeed_ = true;
user_model_.SetValue("value_1_key", value_1_modified.value());
user_model_.SetValue("value_2_key", value_2_modified.value());
user_model_.SetValue("value_3_key", value_3_modified.value());
// Leave value_4 at initial value.
std::move(collect_user_data_options->confirm_callback)
.Run(&user_data_, &user_model_);
}));
ActionProto action_proto;
auto* collect_user_data = action_proto.mutable_collect_user_data();
collect_user_data->set_request_terms_and_conditions(false);
auto* proto_model_prepended =
collect_user_data->mutable_generic_user_interface_prepended()
->mutable_model();
*proto_model_prepended->add_values() = value_1;
*proto_model_prepended->add_values() = value_2;
auto* proto_model_appended =
collect_user_data->mutable_generic_user_interface_appended()
->mutable_model();
*proto_model_appended->add_values() = value_3;
*proto_model_appended->add_values() = value_4;
EXPECT_CALL(
callback_,
Run(Pointee(AllOf(
Property(&ProcessedActionProto::status, ACTION_APPLIED),
Property(&ProcessedActionProto::collect_user_data_result,
Property(&CollectUserDataResultProto::model,
Property(&ModelProto::values,
UnorderedElementsAre(
value_1_modified, value_2_modified,
value_3_modified, value_4))))))));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
}
} // namespace } // namespace
} // namespace autofill_assistant } // namespace autofill_assistant
...@@ -1440,7 +1440,7 @@ message UserFormSectionProto { ...@@ -1440,7 +1440,7 @@ message UserFormSectionProto {
// Asks to provide the data used by UseAddressAction and // Asks to provide the data used by UseAddressAction and
// UseCreditCardAction. // UseCreditCardAction.
// Next: 25 // Next: 26
message CollectUserDataProto { message CollectUserDataProto {
enum TermsAndConditionsState { enum TermsAndConditionsState {
// No choice has been made yet. // No choice has been made yet.
...@@ -1511,8 +1511,12 @@ message CollectUserDataProto { ...@@ -1511,8 +1511,12 @@ message CollectUserDataProto {
repeated UserFormSectionProto additional_prepended_sections = 18; repeated UserFormSectionProto additional_prepended_sections = 18;
// An optional list of additional sections, which is below all other sections. // An optional list of additional sections, which is below all other sections.
repeated UserFormSectionProto additional_appended_sections = 19; repeated UserFormSectionProto additional_appended_sections = 19;
// Backend-configured user interface to show. // Backend-configured user interface to show below
optional GenericUserInterfaceProto generic_user_interface = 22; // |additional_prepended_sections|.
optional GenericUserInterfaceProto generic_user_interface_prepended = 22;
// Backend-configured user interface to show below
// |additional_appended_sections|.
optional GenericUserInterfaceProto generic_user_interface_appended = 25;
// Text to be shown in a separate info section. // Text to be shown in a separate info section.
optional string info_section_text = 24; optional string info_section_text = 24;
} }
......
...@@ -191,7 +191,8 @@ struct CollectUserDataOptions { ...@@ -191,7 +191,8 @@ struct CollectUserDataOptions {
DateTimeRangeProto date_time_range; DateTimeRangeProto date_time_range;
std::vector<UserFormSectionProto> additional_prepended_sections; std::vector<UserFormSectionProto> additional_prepended_sections;
std::vector<UserFormSectionProto> additional_appended_sections; std::vector<UserFormSectionProto> additional_appended_sections;
base::Optional<GenericUserInterfaceProto> generic_user_interface; base::Optional<GenericUserInterfaceProto> generic_user_interface_prepended;
base::Optional<GenericUserInterfaceProto> generic_user_interface_appended;
base::OnceCallback<void(UserData*, const UserModel*)> confirm_callback; base::OnceCallback<void(UserData*, const UserModel*)> confirm_callback;
base::OnceCallback<void(int)> additional_actions_callback; base::OnceCallback<void(int)> additional_actions_callback;
......
...@@ -57,6 +57,13 @@ bool operator==(const ValueProto& value_a, const ValueProto& value_b) { ...@@ -57,6 +57,13 @@ bool operator==(const ValueProto& value_a, const ValueProto& value_b) {
return true; return true;
} }
// Comapres two |ModelValue| instances and returns true if they exactly match.
bool operator==(const ModelProto::ModelValue& value_a,
const ModelProto::ModelValue& value_b) {
return value_a.identifier() == value_b.identifier() &&
value_a.value() == value_b.value();
}
// Intended for debugging. Writes a string representation of |values| to |out|. // Intended for debugging. Writes a string representation of |values| to |out|.
template <typename T> template <typename T>
std::ostream& WriteRepeatedField(std::ostream& out, const T& values) { std::ostream& WriteRepeatedField(std::ostream& out, const T& values) {
......
...@@ -69,6 +69,10 @@ class UserModel { ...@@ -69,6 +69,10 @@ class UserModel {
// |MessageDifferencer| for protobuf lite and can't rely on serialization. // |MessageDifferencer| for protobuf lite and can't rely on serialization.
bool operator==(const ValueProto& value_a, const ValueProto& value_b); bool operator==(const ValueProto& value_a, const ValueProto& value_b);
// Custom comparison operator for |ModelValue|.
bool operator==(const ModelProto::ModelValue& value_a,
const ModelProto::ModelValue& value_b);
// Intended for debugging. // Intended for debugging.
std::ostream& operator<<(std::ostream& out, const ValueProto& value); std::ostream& operator<<(std::ostream& out, const ValueProto& value);
......
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