1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/autofill_assistant/browser/controller.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/json/json_writer.h"
12 #include "base/no_destructor.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/tick_clock.h"
16 #include "base/values.h"
17 #include "components/autofill_assistant/browser/actions/collect_user_data_action.h"
18 #include "components/autofill_assistant/browser/controller_observer.h"
19 #include "components/autofill_assistant/browser/features.h"
20 #include "components/autofill_assistant/browser/metrics.h"
21 #include "components/autofill_assistant/browser/protocol_utils.h"
22 #include "components/autofill_assistant/browser/service/service_impl.h"
23 #include "components/autofill_assistant/browser/trigger_context.h"
24 #include "components/autofill_assistant/browser/url_utils.h"
25 #include "components/autofill_assistant/browser/user_data.h"
26 #include "components/autofill_assistant/browser/view_layout.pb.h"
27 #include "components/google/core/common/google_util.h"
28 #include "components/password_manager/core/browser/password_manager_client.h"
29 #include "components/strings/grit/components_strings.h"
30 #include "content/public/browser/browser_task_traits.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/navigation_handle.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/web_contents.h"
35 #include "net/http/http_status_code.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "url/gurl.h"
38
39 namespace autofill_assistant {
40
41 namespace {
42
43 // The initial progress to set when autostarting and showing the "Loading..."
44 // message.
45 static constexpr int kAutostartInitialProgress = 5;
46
47 // Experiment for toggling the new progress bar.
48 const char kProgressBarExperiment[] = "4400697";
49
50 // Returns true if the state requires a UI to be shown.
51 //
52 // Note that the UI might be shown in RUNNING state, even if it doesn't require
53 // it.
StateNeedsUiInRegularScript(AutofillAssistantState state,bool browse_mode_invisible)54 bool StateNeedsUiInRegularScript(AutofillAssistantState state,
55 bool browse_mode_invisible) {
56 switch (state) {
57 case AutofillAssistantState::PROMPT:
58 case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT:
59 case AutofillAssistantState::MODAL_DIALOG:
60 case AutofillAssistantState::STARTING:
61 return true;
62
63 case AutofillAssistantState::INACTIVE:
64 case AutofillAssistantState::TRACKING:
65 case AutofillAssistantState::STOPPED:
66 case AutofillAssistantState::RUNNING:
67 return false;
68
69 case AutofillAssistantState::BROWSE:
70 return browse_mode_invisible;
71 }
72 }
73
74 // Same as |StateNeedsUiInRegularScript|, but does not show UI in STARTING
75 // state.
StateNeedsUiInLiteScript(AutofillAssistantState state)76 bool StateNeedsUiInLiteScript(AutofillAssistantState state) {
77 switch (state) {
78 case AutofillAssistantState::PROMPT:
79 case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT:
80 case AutofillAssistantState::MODAL_DIALOG:
81 return true;
82
83 case AutofillAssistantState::STARTING:
84 case AutofillAssistantState::BROWSE:
85 case AutofillAssistantState::INACTIVE:
86 case AutofillAssistantState::TRACKING:
87 case AutofillAssistantState::STOPPED:
88 case AutofillAssistantState::RUNNING:
89 return false;
90 }
91 }
92
93 } // namespace
94
Controller(content::WebContents * web_contents,Client * client,const base::TickClock * tick_clock,base::WeakPtr<RuntimeManagerImpl> runtime_manager,std::unique_ptr<Service> service)95 Controller::Controller(content::WebContents* web_contents,
96 Client* client,
97 const base::TickClock* tick_clock,
98 base::WeakPtr<RuntimeManagerImpl> runtime_manager,
99 std::unique_ptr<Service> service)
100 : content::WebContentsObserver(web_contents),
101 client_(client),
102 tick_clock_(tick_clock),
103 runtime_manager_(runtime_manager),
104 service_(service ? std::move(service)
105 : ServiceImpl::Create(web_contents->GetBrowserContext(),
106 client_)),
107 user_data_(std::make_unique<UserData>()),
108 navigating_to_new_document_(web_contents->IsWaitingForResponse()) {
109 user_model_.AddObserver(this);
110 }
111
~Controller()112 Controller::~Controller() {
113 user_model_.RemoveObserver(this);
114 }
115
GetSettings()116 const ClientSettings& Controller::GetSettings() {
117 return settings_;
118 }
119
GetCurrentURL()120 const GURL& Controller::GetCurrentURL() {
121 const GURL& last_committed = web_contents()->GetLastCommittedURL();
122 if (!last_committed.is_empty())
123 return last_committed;
124
125 return deeplink_url_;
126 }
127
GetDeeplinkURL()128 const GURL& Controller::GetDeeplinkURL() {
129 return deeplink_url_;
130 }
131
GetScriptURL()132 const GURL& Controller::GetScriptURL() {
133 return script_url_;
134 }
135
GetService()136 Service* Controller::GetService() {
137 return service_.get();
138 }
139
GetWebController()140 WebController* Controller::GetWebController() {
141 if (!web_controller_) {
142 web_controller_ = WebController::CreateForWebContents(web_contents());
143 }
144 return web_controller_.get();
145 }
146
GetTriggerContext()147 const TriggerContext* Controller::GetTriggerContext() {
148 DCHECK(trigger_context_);
149 return trigger_context_.get();
150 }
151
GetPersonalDataManager()152 autofill::PersonalDataManager* Controller::GetPersonalDataManager() {
153 return client_->GetPersonalDataManager();
154 }
155
GetWebsiteLoginManager()156 WebsiteLoginManager* Controller::GetWebsiteLoginManager() {
157 return client_->GetWebsiteLoginManager();
158 }
159
GetWebContents()160 content::WebContents* Controller::GetWebContents() {
161 return web_contents();
162 }
163
GetEmailAddressForAccessTokenAccount()164 std::string Controller::GetEmailAddressForAccessTokenAccount() {
165 return client_->GetEmailAddressForAccessTokenAccount();
166 }
167
GetLocale()168 std::string Controller::GetLocale() {
169 return client_->GetLocale();
170 }
171
SetTouchableElementArea(const ElementAreaProto & area)172 void Controller::SetTouchableElementArea(const ElementAreaProto& area) {
173 touchable_element_area()->SetFromProto(area);
174 }
175
SetStatusMessage(const std::string & message)176 void Controller::SetStatusMessage(const std::string& message) {
177 status_message_ = message;
178 for (ControllerObserver& observer : observers_) {
179 observer.OnStatusMessageChanged(message);
180 }
181 }
182
GetStatusMessage() const183 std::string Controller::GetStatusMessage() const {
184 return status_message_;
185 }
186
SetBubbleMessage(const std::string & message)187 void Controller::SetBubbleMessage(const std::string& message) {
188 bubble_message_ = message;
189 for (ControllerObserver& observer : observers_) {
190 observer.OnBubbleMessageChanged(message);
191 }
192 }
193
GetBubbleMessage() const194 std::string Controller::GetBubbleMessage() const {
195 return bubble_message_;
196 }
197
SetDetails(std::unique_ptr<Details> details)198 void Controller::SetDetails(std::unique_ptr<Details> details) {
199 details_ = std::move(details);
200 for (ControllerObserver& observer : observers_) {
201 observer.OnDetailsChanged(details_.get());
202 }
203 }
204
GetDetails() const205 const Details* Controller::GetDetails() const {
206 return details_.get();
207 }
208
GetProgress() const209 int Controller::GetProgress() const {
210 return progress_;
211 }
212
GetProgressActiveStep() const213 base::Optional<int> Controller::GetProgressActiveStep() const {
214 return progress_active_step_;
215 }
216
217 base::Optional<ShowProgressBarProto::StepProgressBarConfiguration>
GetStepProgressBarConfiguration() const218 Controller::GetStepProgressBarConfiguration() const {
219 return step_progress_bar_configuration_;
220 }
221
SetInfoBox(const InfoBox & info_box)222 void Controller::SetInfoBox(const InfoBox& info_box) {
223 if (!info_box_) {
224 info_box_ = std::make_unique<InfoBox>();
225 }
226 *info_box_ = info_box;
227 for (ControllerObserver& observer : observers_) {
228 observer.OnInfoBoxChanged(info_box_.get());
229 }
230 }
231
ClearInfoBox()232 void Controller::ClearInfoBox() {
233 info_box_.reset();
234 for (ControllerObserver& observer : observers_) {
235 observer.OnInfoBoxChanged(nullptr);
236 }
237 }
238
GetInfoBox() const239 const InfoBox* Controller::GetInfoBox() const {
240 return info_box_.get();
241 }
242
SetProgress(int progress)243 void Controller::SetProgress(int progress) {
244 // Progress can only increase.
245 if (progress_ >= progress)
246 return;
247
248 progress_ = progress;
249 for (ControllerObserver& observer : observers_) {
250 observer.OnProgressChanged(progress);
251 }
252 }
253
SetProgressActiveStepIdentifier(const std::string & active_step_identifier)254 bool Controller::SetProgressActiveStepIdentifier(
255 const std::string& active_step_identifier) {
256 if (!step_progress_bar_configuration_.has_value()) {
257 return false;
258 }
259
260 auto it = std::find_if(
261 step_progress_bar_configuration_->annotated_step_icons().cbegin(),
262 step_progress_bar_configuration_->annotated_step_icons().cend(),
263 [&](const ShowProgressBarProto::StepProgressBarIcon& icon) {
264 return icon.identifier() == active_step_identifier;
265 });
266 if (it == step_progress_bar_configuration_->annotated_step_icons().cend()) {
267 return false;
268 }
269
270 SetProgressActiveStep(std::distance(
271 step_progress_bar_configuration_->annotated_step_icons().cbegin(), it));
272 return true;
273 }
274
SetProgressActiveStep(int active_step)275 void Controller::SetProgressActiveStep(int active_step) {
276 if (!step_progress_bar_configuration_.has_value()) {
277 return;
278 }
279
280 // Default step progress bar has 2 steps.
281 int max_step = std::max(
282 2, step_progress_bar_configuration_->annotated_step_icons().size());
283
284 int new_active_step = active_step;
285 if (active_step < 0 || active_step > max_step) {
286 new_active_step = max_step;
287 }
288
289 // Step can only increase.
290 if (progress_active_step_.has_value() &&
291 *progress_active_step_ >= new_active_step) {
292 return;
293 }
294
295 progress_active_step_ = new_active_step;
296 for (ControllerObserver& observer : observers_) {
297 observer.OnProgressActiveStepChanged(new_active_step);
298 }
299 }
300
SetProgressVisible(bool visible)301 void Controller::SetProgressVisible(bool visible) {
302 if (progress_visible_ == visible)
303 return;
304
305 progress_visible_ = visible;
306 for (ControllerObserver& observer : observers_) {
307 observer.OnProgressVisibilityChanged(visible);
308 }
309 }
310
GetProgressVisible() const311 bool Controller::GetProgressVisible() const {
312 return progress_visible_;
313 }
314
SetStepProgressBarConfiguration(const ShowProgressBarProto::StepProgressBarConfiguration & configuration)315 void Controller::SetStepProgressBarConfiguration(
316 const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {
317 step_progress_bar_configuration_ = configuration;
318 if (!configuration.annotated_step_icons().empty() &&
319 progress_active_step_.has_value() &&
320 configuration.annotated_step_icons().size() < *progress_active_step_) {
321 progress_active_step_ = configuration.annotated_step_icons().size();
322 }
323 for (ControllerObserver& observer : observers_) {
324 observer.OnStepProgressBarConfigurationChanged(configuration);
325 if (progress_active_step_.has_value()) {
326 observer.OnProgressActiveStepChanged(*progress_active_step_);
327 }
328 observer.OnProgressBarErrorStateChanged(progress_bar_error_state_);
329 }
330 }
331
SetProgressBarErrorState(bool error)332 void Controller::SetProgressBarErrorState(bool error) {
333 if (progress_bar_error_state_ == error) {
334 return;
335 }
336
337 progress_bar_error_state_ = error;
338 for (ControllerObserver& observer : observers_) {
339 observer.OnProgressBarErrorStateChanged(error);
340 }
341 }
342
GetProgressBarErrorState() const343 bool Controller::GetProgressBarErrorState() const {
344 return progress_bar_error_state_;
345 }
346
GetUserActions() const347 const std::vector<UserAction>& Controller::GetUserActions() const {
348 static const base::NoDestructor<std::vector<UserAction>> no_user_actions_;
349 return user_actions_ ? *user_actions_ : *no_user_actions_;
350 }
351
SetUserActions(std::unique_ptr<std::vector<UserAction>> user_actions)352 void Controller::SetUserActions(
353 std::unique_ptr<std::vector<UserAction>> user_actions) {
354 if (user_actions) {
355 SetDefaultChipType(user_actions.get());
356 }
357 user_actions_ = std::move(user_actions);
358 SetVisibilityAndUpdateUserActions();
359 }
360
SetVisibilityAndUpdateUserActions()361 void Controller::SetVisibilityAndUpdateUserActions() {
362 // All non-cancel chips should be hidden while the keyboard is showing.
363 if (user_actions_) {
364 for (UserAction& user_action : *user_actions_) {
365 if (user_action.chip().type != CANCEL_ACTION) {
366 user_action.chip().visible = !is_keyboard_showing_;
367 }
368 }
369 }
370
371 for (ControllerObserver& observer : observers_) {
372 observer.OnUserActionsChanged(GetUserActions());
373 }
374 }
375
IsNavigatingToNewDocument()376 bool Controller::IsNavigatingToNewDocument() {
377 return navigating_to_new_document_;
378 }
379
HasNavigationError()380 bool Controller::HasNavigationError() {
381 return navigation_error_;
382 }
383
RequireUI()384 void Controller::RequireUI() {
385 if (ui_shown_)
386 return;
387
388 needs_ui_ = true;
389 client_->AttachUI();
390 }
391
SetUiShown(bool shown)392 void Controller::SetUiShown(bool shown) {
393 ui_shown_ = shown;
394 if (runtime_manager_) {
395 runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
396 }
397 }
398
SetGenericUi(std::unique_ptr<GenericUserInterfaceProto> generic_ui,base::OnceCallback<void (const ClientStatus &)> end_action_callback,base::OnceCallback<void (const ClientStatus &)> view_inflation_finished_callback)399 void Controller::SetGenericUi(
400 std::unique_ptr<GenericUserInterfaceProto> generic_ui,
401 base::OnceCallback<void(const ClientStatus&)> end_action_callback,
402 base::OnceCallback<void(const ClientStatus&)>
403 view_inflation_finished_callback) {
404 generic_user_interface_ = std::move(generic_ui);
405 basic_interactions_.SetEndActionCallback(std::move(end_action_callback));
406 basic_interactions_.SetViewInflationFinishedCallback(
407 std::move(view_inflation_finished_callback));
408 for (ControllerObserver& observer : observers_) {
409 observer.OnGenericUserInterfaceChanged(generic_user_interface_.get());
410 }
411 }
412
ClearGenericUi()413 void Controller::ClearGenericUi() {
414 generic_user_interface_.reset();
415 basic_interactions_.ClearCallbacks();
416 for (ControllerObserver& observer : observers_) {
417 observer.OnGenericUserInterfaceChanged(nullptr);
418 }
419 }
420
SetBrowseModeInvisible(bool invisible)421 void Controller::SetBrowseModeInvisible(bool invisible) {
422 browse_mode_invisible_ = invisible;
423 }
424
SetShowFeedbackChip(bool show_feedback_chip)425 void Controller::SetShowFeedbackChip(bool show_feedback_chip) {
426 show_feedback_chip_on_graceful_shutdown_ = show_feedback_chip;
427 }
428
AddNavigationListener(ScriptExecutorDelegate::NavigationListener * listener)429 void Controller::AddNavigationListener(
430 ScriptExecutorDelegate::NavigationListener* listener) {
431 navigation_listeners_.AddObserver(listener);
432 }
433
RemoveNavigationListener(ScriptExecutorDelegate::NavigationListener * listener)434 void Controller::RemoveNavigationListener(
435 ScriptExecutorDelegate::NavigationListener* listener) {
436 navigation_listeners_.RemoveObserver(listener);
437 }
438
AddListener(ScriptExecutorDelegate::Listener * listener)439 void Controller::AddListener(ScriptExecutorDelegate::Listener* listener) {
440 listeners_.AddObserver(listener);
441 }
442
RemoveListener(ScriptExecutorDelegate::Listener * listener)443 void Controller::RemoveListener(ScriptExecutorDelegate::Listener* listener) {
444 listeners_.RemoveObserver(listener);
445 }
446
SetExpandSheetForPromptAction(bool expand)447 void Controller::SetExpandSheetForPromptAction(bool expand) {
448 expand_sheet_for_prompt_action_ = expand;
449 }
450
SetBrowseDomainsAllowlist(std::vector<std::string> domains)451 void Controller::SetBrowseDomainsAllowlist(std::vector<std::string> domains) {
452 browse_domains_allowlist_ = std::move(domains);
453 }
454
PerformUserActionWithContext(int index,std::unique_ptr<TriggerContext> context)455 bool Controller::PerformUserActionWithContext(
456 int index,
457 std::unique_ptr<TriggerContext> context) {
458 if (!user_actions_ || index < 0 ||
459 static_cast<size_t>(index) >= user_actions_->size()) {
460 NOTREACHED() << "Invalid user action index: " << index;
461 return false;
462 }
463
464 if (!(*user_actions_)[index].enabled()) {
465 NOTREACHED() << "Action at index " << index << " is disabled.";
466 return false;
467 }
468
469 UserAction user_action = std::move((*user_actions_)[index]);
470 SetUserActions(nullptr);
471 user_action.Call(std::move(context));
472 event_handler_.DispatchEvent(
473 {EventProto::kOnUserActionCalled, user_action.identifier()});
474 return true;
475 }
476
SetViewportMode(ViewportMode mode)477 void Controller::SetViewportMode(ViewportMode mode) {
478 if (mode == viewport_mode_)
479 return;
480
481 viewport_mode_ = mode;
482 for (ControllerObserver& observer : observers_) {
483 observer.OnViewportModeChanged(mode);
484 }
485 }
486
SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode)487 void Controller::SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) {
488 if (peek_mode == peek_mode_)
489 return;
490
491 peek_mode_ = peek_mode;
492 for (ControllerObserver& observer : observers_) {
493 observer.OnPeekModeChanged(peek_mode);
494 }
495 }
496
ExpandBottomSheet()497 void Controller::ExpandBottomSheet() {
498 for (ControllerObserver& observer : observers_) {
499 // TODO(crbug/806868): The interface here and in some of the other On*
500 // events should be coming from the UI layer, not the controller. Or at
501 // least be renamed to something like On*Requested.
502 observer.OnExpandBottomSheet();
503 }
504 }
505
CollapseBottomSheet()506 void Controller::CollapseBottomSheet() {
507 for (ControllerObserver& observer : observers_) {
508 // TODO(crbug/806868): The interface here and in some of the other On*
509 // events should be coming from the UI layer, not the controller. Or at
510 // least be renamed to something like On*Requested.
511 observer.OnCollapseBottomSheet();
512 }
513 }
514
GetForm() const515 const FormProto* Controller::GetForm() const {
516 return form_.get();
517 }
518
GetFormResult() const519 const FormProto::Result* Controller::GetFormResult() const {
520 return form_result_.get();
521 }
522
SetForm(std::unique_ptr<FormProto> form,base::RepeatingCallback<void (const FormProto::Result *)> changed_callback,base::OnceCallback<void (const ClientStatus &)> cancel_callback)523 bool Controller::SetForm(
524 std::unique_ptr<FormProto> form,
525 base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
526 base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
527 form_.reset();
528 form_result_.reset();
529 form_changed_callback_ = base::DoNothing();
530 form_cancel_callback_ = base::DoNothing::Once<const ClientStatus&>();
531
532 if (!form) {
533 for (ControllerObserver& observer : observers_) {
534 observer.OnFormChanged(nullptr, nullptr);
535 }
536 return true;
537 }
538
539 // Initialize form result. This will return false if the form is invalid or
540 // contains unsupported inputs.
541 auto form_result = std::make_unique<FormProto::Result>();
542 for (FormInputProto& input : *form->mutable_inputs()) {
543 FormInputProto::Result* result = form_result->add_input_results();
544 switch (input.input_type_case()) {
545 case FormInputProto::InputTypeCase::kCounter:
546 // Add the initial value of each counter into the form result.
547 for (const CounterInputProto::Counter& counter :
548 input.counter().counters()) {
549 result->mutable_counter()->add_values(counter.initial_value());
550 }
551 break;
552 case FormInputProto::InputTypeCase::kSelection: {
553 // Add the initial selected state of each choice into the form result.
554 bool has_selected = false;
555 for (const SelectionInputProto::Choice& choice :
556 input.selection().choices()) {
557 if (choice.selected()) {
558 if (has_selected && !input.selection().allow_multiple()) {
559 // Multiple choices are initially selected even though it is not
560 // allowed by the input.
561 return false;
562 }
563 has_selected = true;
564 }
565 result->mutable_selection()->add_selected(choice.selected());
566 }
567 break;
568 }
569 case FormInputProto::InputTypeCase::INPUT_TYPE_NOT_SET:
570 VLOG(1) << "Encountered input with INPUT_TYPE_NOT_SET";
571 return false;
572 // Intentionally no default case to make compilation fail if a new value
573 // was added to the enum but not to this list.
574 }
575 }
576
577 // Form is valid.
578 form_ = std::move(form);
579 form_result_ = std::move(form_result);
580 form_changed_callback_ = changed_callback;
581 form_cancel_callback_ = std::move(cancel_callback);
582
583 // Call the callback with initial result.
584 form_changed_callback_.Run(form_result_.get());
585
586 for (ControllerObserver& observer : observers_) {
587 observer.OnFormChanged(form_.get(), form_result_.get());
588 }
589 return true;
590 }
591
SetCounterValue(int input_index,int counter_index,int value)592 void Controller::SetCounterValue(int input_index,
593 int counter_index,
594 int value) {
595 if (!form_result_ || input_index < 0 ||
596 input_index >= form_result_->input_results_size()) {
597 NOTREACHED() << "Invalid input index: " << input_index;
598 return;
599 }
600
601 FormInputProto::Result* input_result =
602 form_result_->mutable_input_results(input_index);
603 if (!input_result->has_counter() || counter_index < 0 ||
604 counter_index >= input_result->counter().values_size()) {
605 NOTREACHED() << "Invalid counter index: " << counter_index;
606 return;
607 }
608
609 input_result->mutable_counter()->set_values(counter_index, value);
610 form_changed_callback_.Run(form_result_.get());
611 }
612
SetChoiceSelected(int input_index,int choice_index,bool selected)613 void Controller::SetChoiceSelected(int input_index,
614 int choice_index,
615 bool selected) {
616 if (!form_result_ || input_index < 0 ||
617 input_index >= form_result_->input_results_size()) {
618 NOTREACHED() << "Invalid input index: " << input_index;
619 return;
620 }
621
622 FormInputProto::Result* input_result =
623 form_result_->mutable_input_results(input_index);
624 if (!input_result->has_selection() || choice_index < 0 ||
625 choice_index >= input_result->selection().selected_size()) {
626 NOTREACHED() << "Invalid choice index: " << choice_index;
627 return;
628 }
629
630 input_result->mutable_selection()->set_selected(choice_index, selected);
631 form_changed_callback_.Run(form_result_.get());
632 }
633
GetUserModel()634 UserModel* Controller::GetUserModel() {
635 return &user_model_;
636 }
637
GetEventHandler()638 EventHandler* Controller::GetEventHandler() {
639 return &event_handler_;
640 }
641
ShouldPromptActionExpandSheet() const642 bool Controller::ShouldPromptActionExpandSheet() const {
643 return expand_sheet_for_prompt_action_;
644 }
645
GetBasicInteractions()646 BasicInteractions* Controller::GetBasicInteractions() {
647 return &basic_interactions_;
648 }
649
GetGenericUiProto() const650 const GenericUserInterfaceProto* Controller::GetGenericUiProto() const {
651 return generic_user_interface_.get();
652 }
653
AddObserver(ControllerObserver * observer)654 void Controller::AddObserver(ControllerObserver* observer) {
655 observers_.AddObserver(observer);
656 }
657
RemoveObserver(const ControllerObserver * observer)658 void Controller::RemoveObserver(const ControllerObserver* observer) {
659 observers_.RemoveObserver(observer);
660 }
661
DispatchEvent(const EventHandler::EventKey & key)662 void Controller::DispatchEvent(const EventHandler::EventKey& key) {
663 event_handler_.DispatchEvent(key);
664 }
665
GetViewportMode()666 ViewportMode Controller::GetViewportMode() {
667 return viewport_mode_;
668 }
669
GetPeekMode()670 ConfigureBottomSheetProto::PeekMode Controller::GetPeekMode() {
671 return peek_mode_;
672 }
673
GetBottomSheetState()674 BottomSheetState Controller::GetBottomSheetState() {
675 return bottom_sheet_state_;
676 }
677
SetBottomSheetState(BottomSheetState state)678 void Controller::SetBottomSheetState(BottomSheetState state) {
679 bottom_sheet_state_ = state;
680 }
681
IsTabSelected()682 bool Controller::IsTabSelected() {
683 return tab_selected_;
684 }
685
SetTabSelected(bool selected)686 void Controller::SetTabSelected(bool selected) {
687 tab_selected_ = selected;
688 }
689
SetOverlayColors(std::unique_ptr<OverlayColors> colors)690 void Controller::SetOverlayColors(std::unique_ptr<OverlayColors> colors) {
691 overlay_colors_ = std::move(colors);
692 if (overlay_colors_) {
693 for (ControllerObserver& observer : observers_) {
694 observer.OnOverlayColorsChanged(*overlay_colors_);
695 }
696 } else {
697 OverlayColors default_colors;
698 for (ControllerObserver& observer : observers_) {
699 observer.OnOverlayColorsChanged(default_colors);
700 }
701 }
702 }
703
GetOverlayColors(OverlayColors * colors) const704 void Controller::GetOverlayColors(OverlayColors* colors) const {
705 if (!overlay_colors_)
706 return;
707 *colors = *overlay_colors_;
708 }
709
GetClientSettings() const710 const ClientSettings& Controller::GetClientSettings() const {
711 return settings_;
712 }
713
ShutdownIfNecessary()714 void Controller::ShutdownIfNecessary() {
715 if (!tracking_) {
716 // We expect the DropOutReason to be already reported when we reach this
717 // point and therefore the reason we pass here in the argument should be
718 // ignored.
719 client_->Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY);
720 }
721 }
722
ReportNavigationStateChanged()723 void Controller::ReportNavigationStateChanged() {
724 for (auto& listener : navigation_listeners_) {
725 listener.OnNavigationStateChanged();
726 }
727 }
728
EnterStoppedState(bool show_feedback_chip)729 void Controller::EnterStoppedState(bool show_feedback_chip) {
730 if (script_tracker_)
731 script_tracker_->StopScript();
732
733 std::unique_ptr<std::vector<UserAction>> final_actions;
734 if (base::FeatureList::IsEnabled(features::kAutofillAssistantFeedbackChip) &&
735 show_feedback_chip) {
736 final_actions = std::make_unique<std::vector<UserAction>>();
737 UserAction feedback_action;
738 Chip feedback_chip;
739 feedback_chip.type = FEEDBACK_ACTION;
740 feedback_chip.text =
741 l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_SEND_FEEDBACK);
742 feedback_action.SetCallback(base::BindOnce(&Controller::ShutdownIfNecessary,
743 weak_ptr_factory_.GetWeakPtr()));
744 feedback_action.chip() = feedback_chip;
745 final_actions->emplace_back(std::move(feedback_action));
746 }
747
748 ClearInfoBox();
749 SetDetails(nullptr);
750 SetUserActions(std::move(final_actions));
751 SetCollectUserDataOptions(nullptr);
752 SetForm(nullptr, base::DoNothing(), base::DoNothing());
753 EnterState(AutofillAssistantState::STOPPED);
754 }
755
EnterState(AutofillAssistantState state)756 bool Controller::EnterState(AutofillAssistantState state) {
757 if (state_ == state)
758 return false;
759
760 VLOG(2) << __func__ << ": " << state_ << " -> " << state;
761
762 // The only valid way of leaving the STOPPED state is to go back to tracking
763 // mode - or going back to RUNNING if it was a recoverable STOPPED state.
764 DCHECK(
765 state_ != AutofillAssistantState::STOPPED ||
766 (state == AutofillAssistantState::TRACKING && tracking_) ||
767 (state == AutofillAssistantState::RUNNING && can_recover_from_stopped_));
768 if (state_ == AutofillAssistantState::STOPPED) {
769 can_recover_from_stopped_ = false;
770 }
771 state_ = state;
772
773 for (ControllerObserver& observer : observers_) {
774 observer.OnStateChanged(state);
775 }
776
777 if (!ui_shown_ && StateNeedsUI(state)) {
778 RequireUI();
779 } else if (needs_ui_ && state == AutofillAssistantState::TRACKING) {
780 needs_ui_ = false;
781 } else if (browse_mode_invisible_ && ui_shown_ &&
782 state == AutofillAssistantState::BROWSE) {
783 needs_ui_ = false;
784 client_->DestroyUI();
785 }
786
787 if (ShouldCheckScripts()) {
788 GetOrCheckScripts();
789 } else {
790 StopPeriodicScriptChecks();
791 }
792 return true;
793 }
794
SetOverlayBehavior(ConfigureUiStateProto::OverlayBehavior overlay_behavior)795 void Controller::SetOverlayBehavior(
796 ConfigureUiStateProto::OverlayBehavior overlay_behavior) {
797 overlay_behavior_ = overlay_behavior;
798 for (ControllerObserver& observer : observers_) {
799 observer.OnShouldShowOverlayChanged(ShouldShowOverlay());
800 }
801 }
802
SetWebControllerForTest(std::unique_ptr<WebController> web_controller)803 void Controller::SetWebControllerForTest(
804 std::unique_ptr<WebController> web_controller) {
805 web_controller_ = std::move(web_controller);
806 }
807
OnUrlChange()808 void Controller::OnUrlChange() {
809 if (state_ == AutofillAssistantState::STOPPED) {
810 PerformDelayedShutdownIfNecessary();
811 return;
812 }
813 user_model_.SetCurrentURL(GetCurrentURL());
814 GetOrCheckScripts();
815 }
816
ShouldCheckScripts()817 bool Controller::ShouldCheckScripts() {
818 return state_ == AutofillAssistantState::TRACKING ||
819 state_ == AutofillAssistantState::STARTING ||
820 state_ == AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT ||
821 ((state_ == AutofillAssistantState::PROMPT ||
822 state_ == AutofillAssistantState::BROWSE) &&
823 (!script_tracker_ || !script_tracker_->running()));
824 }
825
GetOrCheckScripts()826 void Controller::GetOrCheckScripts() {
827 if (!ShouldCheckScripts())
828 return;
829
830 const GURL& url = GetCurrentURL();
831 if (script_url_.host() != url.host()) {
832 StopPeriodicScriptChecks();
833 script_url_ = url;
834 #ifdef NDEBUG
835 VLOG(2) << "GetScripts for <redacted>";
836 #else
837 VLOG(2) << "GetScripts for " << script_url_.host();
838 #endif
839
840 GetService()->GetScriptsForUrl(
841 url, *trigger_context_,
842 base::BindOnce(&Controller::OnGetScripts, base::Unretained(this), url));
843 } else {
844 script_tracker()->CheckScripts();
845 StartPeriodicScriptChecks();
846 }
847 }
848
StartPeriodicScriptChecks()849 void Controller::StartPeriodicScriptChecks() {
850 periodic_script_check_count_ = settings_.periodic_script_check_count;
851 // If periodic checks are running, setting periodic_script_check_count_ keeps
852 // them running longer.
853 if (periodic_script_check_scheduled_)
854 return;
855 periodic_script_check_scheduled_ = true;
856 content::GetUIThreadTaskRunner({})->PostDelayedTask(
857 FROM_HERE,
858 base::BindOnce(&Controller::OnPeriodicScriptCheck,
859 weak_ptr_factory_.GetWeakPtr()),
860 settings_.periodic_script_check_interval);
861 }
862
StopPeriodicScriptChecks()863 void Controller::StopPeriodicScriptChecks() {
864 periodic_script_check_count_ = 0;
865 }
866
OnPeriodicScriptCheck()867 void Controller::OnPeriodicScriptCheck() {
868 if (periodic_script_check_count_ > 0) {
869 periodic_script_check_count_--;
870 }
871
872 if (periodic_script_check_count_ <= 0 && !allow_autostart()) {
873 DCHECK_EQ(0, periodic_script_check_count_);
874 periodic_script_check_scheduled_ = false;
875 return;
876 }
877
878 if (allow_autostart() && !autostart_timeout_script_path_.empty() &&
879 tick_clock_->NowTicks() >= absolute_autostart_timeout_) {
880 VLOG(1) << __func__ << " giving up waiting on autostart.";
881 std::string script_path = autostart_timeout_script_path_;
882 autostart_timeout_script_path_.clear();
883 periodic_script_check_scheduled_ = false;
884 ExecuteScript(script_path, /* start_message= */ "", /* needs_ui= */ false,
885 TriggerContext::CreateEmpty(), state_);
886 return;
887 }
888
889 script_tracker()->CheckScripts();
890 content::GetUIThreadTaskRunner({})->PostDelayedTask(
891 FROM_HERE,
892 base::BindOnce(&Controller::OnPeriodicScriptCheck,
893 weak_ptr_factory_.GetWeakPtr()),
894 settings_.periodic_script_check_interval);
895 }
896
OnGetScripts(const GURL & url,int http_status,const std::string & response)897 void Controller::OnGetScripts(const GURL& url,
898 int http_status,
899 const std::string& response) {
900 if (state_ == AutofillAssistantState::STOPPED)
901 return;
902
903 // If the domain of the current URL changed since the request was sent, the
904 // response is not relevant anymore and can be safely discarded.
905 if (script_url_.host() != url.host())
906 return;
907
908 if (http_status != net::HTTP_OK) {
909 #ifdef NDEBUG
910 VLOG(1) << "Failed to get assistant scripts for <redacted>, http-status="
911 << http_status;
912 #else
913 VLOG(1) << "Failed to get assistant scripts for " << script_url_.host()
914 << ", http-status=" << http_status;
915 #endif
916 OnFatalError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
917 /*show_feedback_chip=*/true,
918 Metrics::DropOutReason::GET_SCRIPTS_FAILED);
919 return;
920 }
921
922 SupportsScriptResponseProto response_proto;
923 if (!response_proto.ParseFromString(response)) {
924 #ifdef NDEBUG
925 VLOG(2) << __func__ << " from <redacted> returned unparseable response";
926 #else
927 VLOG(2) << __func__ << " from " << script_url_.host() << " returned "
928 << "unparseable response";
929 #endif
930 OnFatalError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
931 /*show_feedback_chip=*/true,
932 Metrics::DropOutReason::GET_SCRIPTS_UNPARSABLE);
933 return;
934 }
935 if (response_proto.has_client_settings()) {
936 settings_.UpdateFromProto(response_proto.client_settings());
937 for (ControllerObserver& observer : observers_) {
938 observer.OnClientSettingsChanged(settings_);
939 }
940 }
941
942 std::vector<std::unique_ptr<Script>> scripts;
943 for (const auto& script_proto : response_proto.scripts()) {
944 ProtocolUtils::AddScript(script_proto, &scripts);
945 }
946
947 autostart_timeout_script_path_ =
948 response_proto.script_timeout_error().script_path();
949 autostart_timeout_ = base::TimeDelta::FromMilliseconds(
950 response_proto.script_timeout_error().timeout_ms());
951 if (allow_autostart())
952 absolute_autostart_timeout_ = tick_clock_->NowTicks() + autostart_timeout_;
953
954 #ifdef NDEBUG
955 VLOG(2) << __func__ << " from <redacted> returned " << scripts.size()
956 << " scripts";
957 #else
958 VLOG(2) << __func__ << " from " << script_url_.host() << " returned "
959 << scripts.size() << " scripts";
960 #endif
961
962 if (VLOG_IS_ON(3)) {
963 for (const auto& script : scripts) {
964 // Strip domain from beginning if possible (redundant with log above).
965 auto pos = script->handle.path.find(script_url_.host());
966 if (pos == 0) {
967 DVLOG(3) << "\t"
968 << script->handle.path.substr(script_url_.host().length());
969 } else {
970 DVLOG(3) << "\t" << script->handle.path;
971 }
972 }
973 }
974
975 if (scripts.empty()) {
976 script_tracker()->SetScripts({});
977
978 if (state_ == AutofillAssistantState::TRACKING) {
979 OnFatalError(
980 l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
981 /*show_feedback_chip=*/false, Metrics::DropOutReason::NO_SCRIPTS);
982 return;
983 }
984 OnNoRunnableScriptsForPage();
985 }
986
987 script_tracker()->SetScripts(std::move(scripts));
988 GetOrCheckScripts();
989 }
990
ExecuteScript(const std::string & script_path,const std::string & start_message,bool needs_ui,std::unique_ptr<TriggerContext> context,AutofillAssistantState end_state)991 void Controller::ExecuteScript(const std::string& script_path,
992 const std::string& start_message,
993 bool needs_ui,
994 std::unique_ptr<TriggerContext> context,
995 AutofillAssistantState end_state) {
996 DCHECK(!script_tracker()->running());
997
998 if (!start_message.empty())
999 SetStatusMessage(start_message);
1000
1001 EnterState(AutofillAssistantState::RUNNING);
1002 if (needs_ui)
1003 RequireUI();
1004
1005 touchable_element_area()->Clear();
1006
1007 // Runnable scripts will be checked and reported if necessary after executing
1008 // the script.
1009 script_tracker_->ClearRunnableScripts();
1010 SetUserActions(nullptr);
1011 // TODO(crbug.com/806868): Consider making ClearRunnableScripts part of
1012 // ExecuteScripts to simplify the controller.
1013 script_tracker()->ExecuteScript(
1014 script_path, user_data_.get(), std::move(context),
1015 base::BindOnce(&Controller::OnScriptExecuted,
1016 // script_tracker_ is owned by Controller.
1017 base::Unretained(this), script_path, end_state));
1018 }
1019
OnScriptExecuted(const std::string & script_path,AutofillAssistantState end_state,const ScriptExecutor::Result & result)1020 void Controller::OnScriptExecuted(const std::string& script_path,
1021 AutofillAssistantState end_state,
1022 const ScriptExecutor::Result& result) {
1023 if (!result.success) {
1024 #ifdef NDEBUG
1025 VLOG(1) << "Failed to execute script";
1026 #else
1027 DVLOG(1) << "Failed to execute script " << script_path;
1028 #endif
1029
1030 OnScriptError(
1031 l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
1032 Metrics::DropOutReason::SCRIPT_FAILED);
1033 return;
1034 }
1035
1036 if (result.touchable_element_area) {
1037 touchable_element_area()->SetFromProto(*result.touchable_element_area);
1038 }
1039
1040 switch (result.at_end) {
1041 case ScriptExecutor::SHUTDOWN:
1042 if (!tracking_) {
1043 client_->Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
1044 return;
1045 }
1046 end_state = AutofillAssistantState::TRACKING;
1047 break;
1048
1049 case ScriptExecutor::SHUTDOWN_GRACEFULLY:
1050 if (!tracking_) {
1051 EnterStoppedState(
1052 /*show_feedback_chip=*/show_feedback_chip_on_graceful_shutdown_);
1053 RecordDropOutOrShutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
1054 return;
1055 }
1056 end_state = AutofillAssistantState::TRACKING;
1057 break;
1058
1059 case ScriptExecutor::CLOSE_CUSTOM_TAB:
1060 for (ControllerObserver& observer : observers_) {
1061 observer.CloseCustomTab();
1062 }
1063 if (!tracking_) {
1064 client_->Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED);
1065 return;
1066 }
1067 end_state = AutofillAssistantState::TRACKING;
1068 return;
1069
1070 case ScriptExecutor::CONTINUE:
1071 break;
1072
1073 default:
1074 VLOG(1) << "Unexpected value for at_end: " << result.at_end;
1075 break;
1076 }
1077 EnterState(end_state);
1078 }
1079
MaybeAutostartScript(const std::vector<ScriptHandle> & runnable_scripts)1080 bool Controller::MaybeAutostartScript(
1081 const std::vector<ScriptHandle>& runnable_scripts) {
1082 // Under specific conditions, we can directly run a non-interrupt script
1083 // without first displaying it. This is meant to work only at the very
1084 // beginning, when no scripts have run, and only if there's exactly one
1085 // autostartable script.
1086 if (!allow_autostart())
1087 return false;
1088
1089 int autostart_index = -1;
1090 for (size_t i = 0; i < runnable_scripts.size(); i++) {
1091 if (runnable_scripts[i].autostart) {
1092 if (autostart_index != -1) {
1093 // To many autostartable scripts.
1094 return false;
1095 }
1096 autostart_index = i;
1097 }
1098 }
1099
1100 if (autostart_index == -1)
1101 return false;
1102
1103 // Copying the strings is necessary, as ExecuteScript will invalidate
1104 // runnable_scripts by calling ScriptTracker::ClearRunnableScripts.
1105 //
1106 // TODO(b/138367403): Cleanup this dangerous issue.
1107 std::string path = runnable_scripts[autostart_index].path;
1108 std::string start_message = runnable_scripts[autostart_index].start_message;
1109 bool needs_ui = runnable_scripts[autostart_index].needs_ui;
1110 ExecuteScript(path, start_message, needs_ui, TriggerContext::CreateEmpty(),
1111 AutofillAssistantState::PROMPT);
1112 return true;
1113 }
1114
InitFromParameters()1115 void Controller::InitFromParameters() {
1116 auto details = std::make_unique<Details>();
1117 if (details->UpdateFromParameters(*trigger_context_))
1118 SetDetails(std::move(details));
1119
1120 const base::Optional<std::string> overlay_color =
1121 trigger_context_->GetOverlayColors();
1122 if (overlay_color) {
1123 std::unique_ptr<OverlayColors> colors = std::make_unique<OverlayColors>();
1124 std::vector<std::string> color_strings =
1125 base::SplitString(overlay_color.value(), ":", base::KEEP_WHITESPACE,
1126 base::SPLIT_WANT_ALL);
1127 if (color_strings.size() > 0) {
1128 colors->background = color_strings[0];
1129 }
1130 if (color_strings.size() > 1) {
1131 colors->highlight_border = color_strings[1];
1132 }
1133 // Ignore other colors, to allow future versions of the client to support
1134 // setting more colors.
1135
1136 SetOverlayColors(std::move(colors));
1137 }
1138 const base::Optional<std::string> password_change_username =
1139 trigger_context_->GetPasswordChangeUsername();
1140 if (password_change_username) {
1141 DCHECK(
1142 GetCurrentURL().is_valid()); // At least |deeplink_url_| must be set.
1143 user_data_->selected_login_.emplace(GetCurrentURL().GetOrigin(),
1144 *password_change_username);
1145 }
1146
1147 if (trigger_context_->HasExperimentId(kProgressBarExperiment)) {
1148 ShowProgressBarProto::StepProgressBarConfiguration mock_configuration;
1149 mock_configuration.set_use_step_progress_bar(true);
1150 SetStepProgressBarConfiguration(mock_configuration);
1151 }
1152
1153 user_model_.SetCurrentURL(GetCurrentURL());
1154 }
1155
Track(std::unique_ptr<TriggerContext> trigger_context,base::OnceCallback<void ()> on_first_check_done)1156 void Controller::Track(std::unique_ptr<TriggerContext> trigger_context,
1157 base::OnceCallback<void()> on_first_check_done) {
1158 tracking_ = true;
1159
1160 if (state_ == AutofillAssistantState::INACTIVE) {
1161 trigger_context_ = std::move(trigger_context);
1162 InitFromParameters();
1163 EnterState(AutofillAssistantState::TRACKING);
1164 }
1165
1166 if (on_first_check_done) {
1167 if (has_run_first_check_) {
1168 std::move(on_first_check_done).Run();
1169 } else {
1170 on_has_run_first_check_.emplace_back(std::move(on_first_check_done));
1171 }
1172 }
1173 }
1174
HasRunFirstCheck() const1175 bool Controller::HasRunFirstCheck() const {
1176 return tracking_ && has_run_first_check_;
1177 }
1178
Start(const GURL & deeplink_url,std::unique_ptr<TriggerContext> trigger_context)1179 bool Controller::Start(const GURL& deeplink_url,
1180 std::unique_ptr<TriggerContext> trigger_context) {
1181 if (state_ != AutofillAssistantState::INACTIVE &&
1182 state_ != AutofillAssistantState::TRACKING) {
1183 return false;
1184 }
1185
1186 trigger_context_ = std::move(trigger_context);
1187 deeplink_url_ = deeplink_url;
1188 InitFromParameters();
1189
1190 // Force a re-evaluation of the script, to get a chance to autostart.
1191 if (state_ == AutofillAssistantState::TRACKING)
1192 script_tracker_->ClearRunnableScripts();
1193
1194 if (IsNavigatingToNewDocument()) {
1195 start_after_navigation_ = base::BindOnce(
1196 &Controller::ShowFirstMessageAndStart, weak_ptr_factory_.GetWeakPtr());
1197 } else {
1198 ShowFirstMessageAndStart();
1199 }
1200 return true;
1201 }
1202
ShowFirstMessageAndStart()1203 void Controller::ShowFirstMessageAndStart() {
1204 if (!status_message_.empty()) {
1205 // A status message may have been set prior to calling |Start|.
1206 SetStatusMessage(status_message_);
1207 } else if (!(GetTriggerContext()->is_onboarding_shown() &&
1208 GetTriggerContext()->WasStartedByLegacyTriggerScript())) {
1209 SetStatusMessage(
1210 l10n_util::GetStringFUTF8(IDS_AUTOFILL_ASSISTANT_LOADING,
1211 base::UTF8ToUTF16(GetCurrentURL().host())));
1212 } else {
1213 // Only show default status message if necessary. Scripts started by lite
1214 // scripts that also showed the onboarding do not show the loading message.
1215 }
1216 if (step_progress_bar_configuration_.has_value() &&
1217 step_progress_bar_configuration_->use_step_progress_bar()) {
1218 if (!progress_active_step_.has_value()) {
1219 // Set default progress unless already specified in
1220 // |progress_active_step_|.
1221 progress_active_step_ = 0;
1222 }
1223 SetStepProgressBarConfiguration(*step_progress_bar_configuration_);
1224 SetProgressActiveStep(*progress_active_step_);
1225 } else {
1226 SetProgress(kAutostartInitialProgress);
1227 }
1228 EnterState(AutofillAssistantState::STARTING);
1229 }
1230
GetState() const1231 AutofillAssistantState Controller::GetState() const {
1232 return state_;
1233 }
1234
ShouldShowOverlay() const1235 bool Controller::ShouldShowOverlay() const {
1236 return overlay_behavior_ == ConfigureUiStateProto::DEFAULT;
1237 }
1238
OnScriptSelected(const ScriptHandle & handle,std::unique_ptr<TriggerContext> context)1239 void Controller::OnScriptSelected(const ScriptHandle& handle,
1240 std::unique_ptr<TriggerContext> context) {
1241 ExecuteScript(handle.path, handle.start_message, handle.needs_ui,
1242 std::move(context),
1243 state_ == AutofillAssistantState::TRACKING
1244 ? AutofillAssistantState::TRACKING
1245 : AutofillAssistantState::PROMPT);
1246 }
1247
OnUserInteractionInsideTouchableArea()1248 void Controller::OnUserInteractionInsideTouchableArea() {
1249 GetOrCheckScripts();
1250 }
1251
GetDebugContext()1252 std::string Controller::GetDebugContext() {
1253 base::Value dict(base::Value::Type::DICTIONARY);
1254
1255 dict.SetKey("status", base::Value(status_message_));
1256 if (trigger_context_) {
1257 std::vector<base::Value> parameters_js;
1258 for (const auto& parameter : trigger_context_->GetParameters()) {
1259 base::Value parameter_js = base::Value(base::Value::Type::DICTIONARY);
1260 parameter_js.SetKey(parameter.first, base::Value(parameter.second));
1261 parameters_js.push_back(std::move(parameter_js));
1262 }
1263 dict.SetKey("parameters", base::Value(parameters_js));
1264 }
1265 dict.SetKey("scripts", script_tracker()->GetDebugContext());
1266
1267 if (details_)
1268 dict.SetKey("details", details_->GetDebugContext());
1269
1270 std::string output_js;
1271 base::JSONWriter::Write(dict, &output_js);
1272 return output_js;
1273 }
1274
GetCollectUserDataOptions() const1275 const CollectUserDataOptions* Controller::GetCollectUserDataOptions() const {
1276 return collect_user_data_options_;
1277 }
1278
GetUserData() const1279 const UserData* Controller::GetUserData() const {
1280 return user_data_.get();
1281 }
1282
OnCollectUserDataContinueButtonClicked()1283 void Controller::OnCollectUserDataContinueButtonClicked() {
1284 if (!collect_user_data_options_ || !user_data_)
1285 return;
1286
1287 auto callback = std::move(collect_user_data_options_->confirm_callback);
1288
1289 SetCollectUserDataOptions(nullptr);
1290 std::move(callback).Run(user_data_.get(), &user_model_);
1291 }
1292
OnCollectUserDataAdditionalActionTriggered(int index)1293 void Controller::OnCollectUserDataAdditionalActionTriggered(int index) {
1294 if (!collect_user_data_options_)
1295 return;
1296
1297 auto callback =
1298 std::move(collect_user_data_options_->additional_actions_callback);
1299 SetCollectUserDataOptions(nullptr);
1300 std::move(callback).Run(index, user_data_.get(), &user_model_);
1301 }
1302
OnTextLinkClicked(int link)1303 void Controller::OnTextLinkClicked(int link) {
1304 if (!user_data_)
1305 return;
1306
1307 auto callback = std::move(collect_user_data_options_->terms_link_callback);
1308 SetCollectUserDataOptions(nullptr);
1309 std::move(callback).Run(link, user_data_.get(), &user_model_);
1310 }
1311
OnFormActionLinkClicked(int link)1312 void Controller::OnFormActionLinkClicked(int link) {
1313 if (form_cancel_callback_ && form_result_ != nullptr) {
1314 form_result_->set_link(link);
1315 form_changed_callback_.Run(form_result_.get());
1316 std::move(form_cancel_callback_).Run(ClientStatus(ACTION_APPLIED));
1317 }
1318 }
1319
SetDateTimeRangeStartDate(const base::Optional<DateProto> & date)1320 void Controller::SetDateTimeRangeStartDate(
1321 const base::Optional<DateProto>& date) {
1322 if (!user_data_)
1323 return;
1324
1325 if (user_data_->date_time_range_start_date_.has_value() && date.has_value() &&
1326 CollectUserDataAction::CompareDates(
1327 *user_data_->date_time_range_start_date_, *date) == 0) {
1328 return;
1329 }
1330
1331 user_data_->date_time_range_start_date_ = date;
1332 for (ControllerObserver& observer : observers_) {
1333 observer.OnUserDataChanged(user_data_.get(),
1334 UserData::FieldChange::DATE_TIME_RANGE_START);
1335 }
1336
1337 if (CollectUserDataAction::SanitizeDateTimeRange(
1338 &user_data_->date_time_range_start_date_,
1339 &user_data_->date_time_range_start_timeslot_,
1340 &user_data_->date_time_range_end_date_,
1341 &user_data_->date_time_range_end_timeslot_,
1342 *collect_user_data_options_,
1343 /* change_start = */ false)) {
1344 for (ControllerObserver& observer : observers_) {
1345 observer.OnUserDataChanged(user_data_.get(),
1346 UserData::FieldChange::DATE_TIME_RANGE_END);
1347 }
1348 }
1349
1350 UpdateCollectUserDataActions();
1351 }
1352
SetDateTimeRangeStartTimeSlot(const base::Optional<int> & timeslot_index)1353 void Controller::SetDateTimeRangeStartTimeSlot(
1354 const base::Optional<int>& timeslot_index) {
1355 if (!user_data_)
1356 return;
1357
1358 if (user_data_->date_time_range_start_timeslot_.has_value() &&
1359 timeslot_index.has_value() &&
1360 *user_data_->date_time_range_start_timeslot_ == *timeslot_index) {
1361 return;
1362 }
1363
1364 user_data_->date_time_range_start_timeslot_ = timeslot_index;
1365 for (ControllerObserver& observer : observers_) {
1366 observer.OnUserDataChanged(user_data_.get(),
1367 UserData::FieldChange::DATE_TIME_RANGE_START);
1368 }
1369
1370 if (CollectUserDataAction::SanitizeDateTimeRange(
1371 &user_data_->date_time_range_start_date_,
1372 &user_data_->date_time_range_start_timeslot_,
1373 &user_data_->date_time_range_end_date_,
1374 &user_data_->date_time_range_end_timeslot_,
1375 *collect_user_data_options_,
1376 /* change_start = */ false)) {
1377 for (ControllerObserver& observer : observers_) {
1378 observer.OnUserDataChanged(user_data_.get(),
1379 UserData::FieldChange::DATE_TIME_RANGE_END);
1380 }
1381 }
1382
1383 UpdateCollectUserDataActions();
1384 }
1385
SetDateTimeRangeEndDate(const base::Optional<DateProto> & date)1386 void Controller::SetDateTimeRangeEndDate(
1387 const base::Optional<DateProto>& date) {
1388 if (!user_data_)
1389 return;
1390
1391 if (user_data_->date_time_range_end_date_.has_value() && date.has_value() &&
1392 CollectUserDataAction::CompareDates(
1393 *user_data_->date_time_range_end_date_, *date) == 0) {
1394 return;
1395 }
1396
1397 user_data_->date_time_range_end_date_ = date;
1398 for (ControllerObserver& observer : observers_) {
1399 observer.OnUserDataChanged(user_data_.get(),
1400 UserData::FieldChange::DATE_TIME_RANGE_END);
1401 }
1402
1403 if (CollectUserDataAction::SanitizeDateTimeRange(
1404 &user_data_->date_time_range_start_date_,
1405 &user_data_->date_time_range_start_timeslot_,
1406 &user_data_->date_time_range_end_date_,
1407 &user_data_->date_time_range_end_timeslot_,
1408 *collect_user_data_options_,
1409 /* change_start = */ true)) {
1410 for (ControllerObserver& observer : observers_) {
1411 observer.OnUserDataChanged(user_data_.get(),
1412 UserData::FieldChange::DATE_TIME_RANGE_START);
1413 }
1414 }
1415
1416 UpdateCollectUserDataActions();
1417 }
1418
SetDateTimeRangeEndTimeSlot(const base::Optional<int> & timeslot_index)1419 void Controller::SetDateTimeRangeEndTimeSlot(
1420 const base::Optional<int>& timeslot_index) {
1421 if (!user_data_)
1422 return;
1423
1424 if (user_data_->date_time_range_end_timeslot_.has_value() &&
1425 timeslot_index.has_value() &&
1426 *user_data_->date_time_range_end_timeslot_ == *timeslot_index) {
1427 return;
1428 }
1429
1430 user_data_->date_time_range_end_timeslot_ = timeslot_index;
1431 for (ControllerObserver& observer : observers_) {
1432 observer.OnUserDataChanged(user_data_.get(),
1433 UserData::FieldChange::DATE_TIME_RANGE_END);
1434 }
1435
1436 if (CollectUserDataAction::SanitizeDateTimeRange(
1437 &user_data_->date_time_range_start_date_,
1438 &user_data_->date_time_range_start_timeslot_,
1439 &user_data_->date_time_range_end_date_,
1440 &user_data_->date_time_range_end_timeslot_,
1441 *collect_user_data_options_,
1442 /* change_start = */ true)) {
1443 for (ControllerObserver& observer : observers_) {
1444 observer.OnUserDataChanged(user_data_.get(),
1445 UserData::FieldChange::DATE_TIME_RANGE_START);
1446 }
1447 }
1448
1449 UpdateCollectUserDataActions();
1450 }
1451
SetAdditionalValue(const std::string & client_memory_key,const ValueProto & value)1452 void Controller::SetAdditionalValue(const std::string& client_memory_key,
1453 const ValueProto& value) {
1454 if (!user_data_)
1455 return;
1456 auto it = user_data_->additional_values_.find(client_memory_key);
1457 if (it == user_data_->additional_values_.end()) {
1458 NOTREACHED() << client_memory_key << " not found";
1459 return;
1460 }
1461 it->second = value;
1462 UpdateCollectUserDataActions();
1463 for (ControllerObserver& observer : observers_) {
1464 observer.OnUserDataChanged(user_data_.get(),
1465 UserData::FieldChange::ADDITIONAL_VALUES);
1466 }
1467 }
1468
SetShippingAddress(std::unique_ptr<autofill::AutofillProfile> address)1469 void Controller::SetShippingAddress(
1470 std::unique_ptr<autofill::AutofillProfile> address) {
1471 if (collect_user_data_options_ == nullptr) {
1472 return;
1473 }
1474
1475 DCHECK(!collect_user_data_options_->shipping_address_name.empty());
1476 SetProfile(collect_user_data_options_->shipping_address_name,
1477 UserData::FieldChange::SHIPPING_ADDRESS, std::move(address));
1478 }
1479
SetContactInfo(std::unique_ptr<autofill::AutofillProfile> profile)1480 void Controller::SetContactInfo(
1481 std::unique_ptr<autofill::AutofillProfile> profile) {
1482 if (collect_user_data_options_ == nullptr) {
1483 return;
1484 }
1485
1486 DCHECK(!collect_user_data_options_->contact_details_name.empty());
1487 SetProfile(collect_user_data_options_->contact_details_name,
1488 UserData::FieldChange::CONTACT_PROFILE, std::move(profile));
1489 }
1490
SetCreditCard(std::unique_ptr<autofill::CreditCard> card,std::unique_ptr<autofill::AutofillProfile> billing_profile)1491 void Controller::SetCreditCard(
1492 std::unique_ptr<autofill::CreditCard> card,
1493 std::unique_ptr<autofill::AutofillProfile> billing_profile) {
1494 if (user_data_ == nullptr || collect_user_data_options_ == nullptr) {
1495 return;
1496 }
1497
1498 DCHECK(!collect_user_data_options_->billing_address_name.empty());
1499
1500 user_data_->selected_card_ = std::move(card);
1501 for (ControllerObserver& observer : observers_) {
1502 observer.OnUserDataChanged(user_data_.get(), UserData::FieldChange::CARD);
1503 }
1504 SetProfile(collect_user_data_options_->billing_address_name,
1505 UserData::FieldChange::BILLING_ADDRESS,
1506 std::move(billing_profile));
1507 }
1508
SetProfile(const std::string & key,UserData::FieldChange field_change,std::unique_ptr<autofill::AutofillProfile> profile)1509 void Controller::SetProfile(
1510 const std::string& key,
1511 UserData::FieldChange field_change,
1512 std::unique_ptr<autofill::AutofillProfile> profile) {
1513 if (user_data_ == nullptr) {
1514 return;
1515 }
1516
1517 auto it = user_data_->selected_addresses_.find(key);
1518 if (it != user_data_->selected_addresses_.end()) {
1519 user_data_->selected_addresses_.erase(it);
1520 }
1521 if (profile != nullptr) {
1522 user_data_->selected_addresses_.emplace(key, std::move(profile));
1523 }
1524
1525 for (ControllerObserver& observer : observers_) {
1526 observer.OnUserDataChanged(user_data_.get(), field_change);
1527 }
1528 UpdateCollectUserDataActions();
1529 }
1530
SetTermsAndConditions(TermsAndConditionsState terms_and_conditions)1531 void Controller::SetTermsAndConditions(
1532 TermsAndConditionsState terms_and_conditions) {
1533 if (!user_data_)
1534 return;
1535
1536 user_data_->terms_and_conditions_ = terms_and_conditions;
1537 UpdateCollectUserDataActions();
1538 for (ControllerObserver& observer : observers_) {
1539 observer.OnUserDataChanged(user_data_.get(),
1540 UserData::FieldChange::TERMS_AND_CONDITIONS);
1541 }
1542 }
1543
SetLoginOption(std::string identifier)1544 void Controller::SetLoginOption(std::string identifier) {
1545 if (!user_data_ || !collect_user_data_options_)
1546 return;
1547
1548 user_data_->login_choice_identifier_.assign(identifier);
1549 UpdateCollectUserDataActions();
1550 for (ControllerObserver& observer : observers_) {
1551 observer.OnUserDataChanged(user_data_.get(),
1552 UserData::FieldChange::LOGIN_CHOICE);
1553 }
1554 }
1555
UpdateCollectUserDataActions()1556 void Controller::UpdateCollectUserDataActions() {
1557 // TODO(crbug.com/806868): This method uses #SetUserActions(), which means
1558 // that updating the PR action buttons will also clear the suggestions. We
1559 // should update the action buttons only if there are use cases of PR +
1560 // suggestions.
1561 if (!collect_user_data_options_ || !user_data_) {
1562 SetUserActions(nullptr);
1563 return;
1564 }
1565
1566 bool confirm_button_enabled = CollectUserDataAction::IsUserDataComplete(
1567 *user_data_, user_model_, *collect_user_data_options_);
1568
1569 UserAction confirm(collect_user_data_options_->confirm_action);
1570 confirm.SetEnabled(confirm_button_enabled);
1571 if (confirm_button_enabled) {
1572 confirm.SetCallback(
1573 base::BindOnce(&Controller::OnCollectUserDataContinueButtonClicked,
1574 weak_ptr_factory_.GetWeakPtr()));
1575 }
1576
1577 auto user_actions = std::make_unique<std::vector<UserAction>>();
1578 user_actions->emplace_back(std::move(confirm));
1579
1580 // Add additional actions.
1581 for (size_t i = 0; i < collect_user_data_options_->additional_actions.size();
1582 ++i) {
1583 auto action = collect_user_data_options_->additional_actions[i];
1584 user_actions->push_back({action});
1585 user_actions->back().SetCallback(
1586 base::BindOnce(&Controller::OnCollectUserDataAdditionalActionTriggered,
1587 weak_ptr_factory_.GetWeakPtr(), i));
1588 }
1589
1590 SetUserActions(std::move(user_actions));
1591 }
1592
GetTouchableArea(std::vector<RectF> * area) const1593 void Controller::GetTouchableArea(std::vector<RectF>* area) const {
1594 if (touchable_element_area_)
1595 touchable_element_area_->GetTouchableRectangles(area);
1596 }
1597
GetRestrictedArea(std::vector<RectF> * area) const1598 void Controller::GetRestrictedArea(std::vector<RectF>* area) const {
1599 if (touchable_element_area_)
1600 touchable_element_area_->GetRestrictedRectangles(area);
1601 }
1602
GetVisualViewport(RectF * visual_viewport) const1603 void Controller::GetVisualViewport(RectF* visual_viewport) const {
1604 if (touchable_element_area_)
1605 touchable_element_area_->GetVisualViewport(visual_viewport);
1606 }
1607
OnScriptError(const std::string & error_message,Metrics::DropOutReason reason)1608 void Controller::OnScriptError(const std::string& error_message,
1609 Metrics::DropOutReason reason) {
1610 if (state_ == AutofillAssistantState::STOPPED)
1611 return;
1612
1613 // For lite scripts, don't attach the UI on error, and don't show an error
1614 // while shutting down.
1615 if (!IsRunningLiteScript()) {
1616 RequireUI();
1617 SetStatusMessage(error_message);
1618 SetProgressBarErrorState(true);
1619 }
1620
1621 EnterStoppedState(/*show_feedback_chip=*/true);
1622
1623 if (tracking_) {
1624 EnterState(AutofillAssistantState::TRACKING);
1625 return;
1626 }
1627
1628 RecordDropOutOrShutdown(reason);
1629 }
1630
OnFatalError(const std::string & error_message,bool show_feedback_chip,Metrics::DropOutReason reason)1631 void Controller::OnFatalError(const std::string& error_message,
1632 bool show_feedback_chip,
1633 Metrics::DropOutReason reason) {
1634 LOG(ERROR) << "Autofill Assistant has encountered a fatal error and is "
1635 "shutting down, reason="
1636 << reason;
1637 if (state_ == AutofillAssistantState::STOPPED)
1638 return;
1639
1640 SetStatusMessage(error_message);
1641 SetProgressBarErrorState(true);
1642 EnterStoppedState(show_feedback_chip);
1643
1644 // If we haven't managed to check the set of scripts yet at this point, we
1645 // never will.
1646 MaybeReportFirstCheckDone();
1647
1648 if (tracking_ && script_url_.host() == GetCurrentURL().host()) {
1649 // When tracking the controller should stays until the browser has navigated
1650 // away from the last domain that was checked to be able to tell callers
1651 // that the set of user actions is empty.
1652 delayed_shutdown_reason_ = reason;
1653 return;
1654 }
1655
1656 RecordDropOutOrShutdown(reason);
1657 }
1658
RecordDropOutOrShutdown(Metrics::DropOutReason reason)1659 void Controller::RecordDropOutOrShutdown(Metrics::DropOutReason reason) {
1660 // If there is an UI, we wait for it to be closed before shutting down (the UI
1661 // will call |ShutdownIfNecessary|).
1662 // Lite scripts go away immediately, even if UI is currently being shown.
1663 if (client_->HasHadUI() && !IsRunningLiteScript()) {
1664 // We report right away to make sure we don't lose this reason if the client
1665 // is unexpectedly destroyed while the error message is showing (for example
1666 // if the tab is closed).
1667 client_->RecordDropOut(reason);
1668 } else {
1669 client_->Shutdown(reason);
1670 }
1671 }
1672
OnStop(const std::string & message,const std::string & button_label)1673 void Controller::OnStop(const std::string& message,
1674 const std::string& button_label) {
1675 DCHECK(state_ != AutofillAssistantState::STOPPED);
1676
1677 can_recover_from_stopped_ = true;
1678 for (auto& listener : listeners_) {
1679 listener.OnPause(message, button_label);
1680 }
1681 }
1682
PerformDelayedShutdownIfNecessary()1683 void Controller::PerformDelayedShutdownIfNecessary() {
1684 if (delayed_shutdown_reason_ &&
1685 script_url_.host() != GetCurrentURL().host()) {
1686 Metrics::DropOutReason reason = delayed_shutdown_reason_.value();
1687 delayed_shutdown_reason_ = base::nullopt;
1688 tracking_ = false;
1689 client_->Shutdown(reason);
1690 }
1691 }
1692
MaybeReportFirstCheckDone()1693 void Controller::MaybeReportFirstCheckDone() {
1694 if (has_run_first_check_)
1695 return;
1696
1697 has_run_first_check_ = true;
1698
1699 while (!on_has_run_first_check_.empty()) {
1700 std::move(on_has_run_first_check_.back()).Run();
1701 on_has_run_first_check_.pop_back();
1702 }
1703 }
1704
OnNoRunnableScriptsForPage()1705 void Controller::OnNoRunnableScriptsForPage() {
1706 if (script_tracker()->running())
1707 return;
1708
1709 switch (state_) {
1710 case AutofillAssistantState::STARTING:
1711 // We're still waiting for the set of initial scripts, but either didn't
1712 // get any scripts or didn't get scripts that could possibly become
1713 // runnable with a DOM change.
1714 OnScriptError(
1715 l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
1716 Metrics::DropOutReason::NO_INITIAL_SCRIPTS);
1717 break;
1718
1719 case AutofillAssistantState::PROMPT:
1720 case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT:
1721 // The user has navigated to a page that has no scripts or the scripts
1722 // have reached a state from which they cannot recover through a DOM
1723 // change.
1724 OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
1725 Metrics::DropOutReason::NO_SCRIPTS);
1726 break;
1727
1728 default:
1729 // Always having a set of scripts to potentially run is not required in
1730 // other states, for example in BROWSE state.
1731 break;
1732 }
1733 }
1734
OnRunnableScriptsChanged(const std::vector<ScriptHandle> & runnable_scripts)1735 void Controller::OnRunnableScriptsChanged(
1736 const std::vector<ScriptHandle>& runnable_scripts) {
1737 base::ScopedClosureRunner report_first_check;
1738 if (!has_run_first_check_) {
1739 // Only report first check done once we're done processing the given set of
1740 // scripts - whatever the outcome - so callers can see that outcome in the
1741 // state of the controller.
1742 report_first_check.ReplaceClosure(
1743 base::BindOnce(&Controller::MaybeReportFirstCheckDone,
1744 weak_ptr_factory_.GetWeakPtr()));
1745 }
1746
1747 // Script selection is disabled when a script is already running. We will
1748 // check again and maybe update when the current script has finished.
1749 if (script_tracker()->running() || state_ == AutofillAssistantState::STOPPED)
1750 return;
1751
1752 if (MaybeAutostartScript(runnable_scripts)) {
1753 return;
1754 }
1755
1756 // Show the initial prompt if available.
1757 for (const auto& script : runnable_scripts) {
1758 // runnable_scripts is ordered by priority.
1759 if (!script.initial_prompt.empty()) {
1760 SetStatusMessage(script.initial_prompt);
1761 break;
1762 }
1763 }
1764
1765 // Update the set of user actions to report.
1766 auto user_actions = std::make_unique<std::vector<UserAction>>();
1767 for (const auto& script : runnable_scripts) {
1768 UserAction user_action;
1769 user_action.chip() = script.chip;
1770 user_action.direct_action() = script.direct_action;
1771 if (!user_action.has_triggers())
1772 continue;
1773
1774 user_action.SetCallback(base::BindOnce(
1775 &Controller::OnScriptSelected, weak_ptr_factory_.GetWeakPtr(), script));
1776 user_actions->emplace_back(std::move(user_action));
1777 }
1778
1779 // Change state, if necessary.
1780 switch (state_) {
1781 case AutofillAssistantState::TRACKING:
1782 case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT:
1783 case AutofillAssistantState::PROMPT:
1784 case AutofillAssistantState::BROWSE:
1785 // Don't change state
1786 break;
1787
1788 case AutofillAssistantState::STARTING:
1789 if (!user_actions->empty())
1790 EnterState(AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT);
1791 break;
1792
1793 default:
1794 if (!user_actions->empty())
1795 EnterState(AutofillAssistantState::PROMPT);
1796 }
1797 SetUserActions(std::move(user_actions));
1798 }
1799
DidFinishLoad(content::RenderFrameHost * render_frame_host,const GURL & validated_url)1800 void Controller::DidFinishLoad(content::RenderFrameHost* render_frame_host,
1801 const GURL& validated_url) {
1802 // validated_url might not be the page URL. Ignore it and always check the
1803 // last committed url.
1804 OnUrlChange();
1805 }
1806
ExpectNavigation()1807 void Controller::ExpectNavigation() {
1808 expect_navigation_ = true;
1809 }
1810
DidStartNavigation(content::NavigationHandle * navigation_handle)1811 void Controller::DidStartNavigation(
1812 content::NavigationHandle* navigation_handle) {
1813 if (!navigation_handle->IsInMainFrame() ||
1814 navigation_handle->IsSameDocument()) {
1815 return;
1816 }
1817
1818 if (!navigating_to_new_document_) {
1819 navigating_to_new_document_ = true;
1820 ReportNavigationStateChanged();
1821 }
1822
1823 // The navigation is expected, do not check for errors below.
1824 if (expect_navigation_) {
1825 expect_navigation_ = false;
1826 return;
1827 }
1828
1829 if (state_ == AutofillAssistantState::STOPPED &&
1830 !navigation_handle->IsRendererInitiated() &&
1831 !navigation_handle->WasServerRedirect()) {
1832 if (can_recover_from_stopped_) {
1833 // Usually when in STOPPED (e.g. through |OnScriptError|) the
1834 // |DropOutReason| has been recorded. In the case of a recoverable stop,
1835 // e.g. with the back button, this is not the case. Record the reason as
1836 // |NAVIGATION| here.
1837 client_->Shutdown(Metrics::DropOutReason::NAVIGATION);
1838 return;
1839 }
1840
1841 ShutdownIfNecessary();
1842 return;
1843 }
1844
1845 // In lite scripts, navigations are allowed (the lite script will fail if the
1846 // trigger condition stops being true).
1847 //
1848 // In regular scripts, the following types of navigations are allowed for the
1849 // main frame, when in PROMPT state:
1850 // - first-time URL load
1851 // - script-directed navigation, while a script is running unless
1852 // there's a touchable area.
1853 // - server redirections, which might happen outside of a script, but
1854 // because of a load triggered by a previously-running script.
1855 // - same-document modifications, which might happen automatically
1856 // - javascript-initiated navigation or refresh
1857 // - navigation by clicking on a link
1858 // In the last two cases, autofill assistant might still give up later on if
1859 // it discovers that the new page has no scripts.
1860 //
1861 // Everything else, such as going back to a previous page, or refreshing the
1862 // page is considered an end condition. If going back to a previous page is
1863 // required, consider using the BROWSE state instead.
1864 if (!IsRunningLiteScript() && state_ == AutofillAssistantState::PROMPT &&
1865 web_contents()->GetLastCommittedURL().is_valid() &&
1866 !navigation_handle->WasServerRedirect() &&
1867 !navigation_handle->IsRendererInitiated()) {
1868 OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
1869 Metrics::DropOutReason::NAVIGATION);
1870 return;
1871 }
1872
1873 // When in RUNNING state, all renderer initiated navigation is allowed,
1874 // user initiated navigation will cause an error.
1875 if (state_ == AutofillAssistantState::RUNNING &&
1876 !navigation_handle->WasServerRedirect() &&
1877 !navigation_handle->IsRendererInitiated()) {
1878 OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
1879 Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING);
1880 return;
1881 }
1882
1883 // Note that BROWSE state end conditions are in DidFinishNavigation, in order
1884 // to be able to properly evaluate the committed url.
1885 }
1886
DidFinishNavigation(content::NavigationHandle * navigation_handle)1887 void Controller::DidFinishNavigation(
1888 content::NavigationHandle* navigation_handle) {
1889 // TODO(b/159871774): Rethink how we handle navigation events. The early
1890 // return here may prevent us from updating |navigating_to_new_document_|.
1891 if (!navigation_handle->IsInMainFrame() ||
1892 navigation_handle->IsSameDocument() ||
1893 !navigation_handle->HasCommitted() || !IsNavigatingToNewDocument()) {
1894 return;
1895 }
1896
1897 bool is_successful =
1898 !navigation_handle->IsErrorPage() &&
1899 navigation_handle->GetNetErrorCode() == net::OK &&
1900 navigation_handle->GetResponseHeaders() &&
1901 (navigation_handle->GetResponseHeaders()->response_code() / 100) == 2;
1902 navigation_error_ = !is_successful;
1903 navigating_to_new_document_ = false;
1904
1905 // When in BROWSE state, stop autofill assistant if the user navigates away
1906 // from the original assisted domain. Subdomains of the original domain are
1907 // supported.
1908 if (state_ == AutofillAssistantState::BROWSE) {
1909 if (!url_utils::IsInDomainOrSubDomain(GetCurrentURL(), script_url_) &&
1910 !url_utils::IsInDomainOrSubDomain(GetCurrentURL(),
1911 browse_domains_allowlist_)) {
1912 OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
1913 Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE);
1914 }
1915 }
1916 // When in STOPPED state, entered by an unexpected DidStartNavigation or
1917 // domain change while in BROWSE state (above), and the new URL is on a
1918 // Google property, destroy the UI immediately.
1919 if (state_ == AutofillAssistantState::STOPPED &&
1920 google_util::IsGoogleDomainUrl(
1921 web_contents()->GetLastCommittedURL(), google_util::ALLOW_SUBDOMAIN,
1922 google_util::DISALLOW_NON_STANDARD_PORTS)) {
1923 client_->DestroyUI();
1924 }
1925
1926 if (start_after_navigation_) {
1927 std::move(start_after_navigation_).Run();
1928 } else {
1929 ReportNavigationStateChanged();
1930
1931 if (is_successful) {
1932 OnUrlChange();
1933 }
1934 }
1935 }
1936
DocumentAvailableInMainFrame()1937 void Controller::DocumentAvailableInMainFrame() {
1938 OnUrlChange();
1939 }
1940
RenderProcessGone(base::TerminationStatus status)1941 void Controller::RenderProcessGone(base::TerminationStatus status) {
1942 client_->Shutdown(Metrics::DropOutReason::RENDER_PROCESS_GONE);
1943 }
1944
OnWebContentsFocused(content::RenderWidgetHost * render_widget_host)1945 void Controller::OnWebContentsFocused(
1946 content::RenderWidgetHost* render_widget_host) {
1947 if (NeedsUI() &&
1948 base::FeatureList::IsEnabled(features::kAutofillAssistantChromeEntry)) {
1949 // Show UI again when re-focused in case the web contents moved activity.
1950 // This is only enabled when tab-switching is enabled.
1951 client_->AttachUI();
1952 }
1953 }
1954
OnValueChanged(const std::string & identifier,const ValueProto & new_value)1955 void Controller::OnValueChanged(const std::string& identifier,
1956 const ValueProto& new_value) {
1957 event_handler_.DispatchEvent({EventProto::kOnValueChanged, identifier});
1958 // TODO(b/145043394) Remove this once chips are part of generic UI.
1959 if (collect_user_data_options_ != nullptr &&
1960 collect_user_data_options_->additional_model_identifier_to_check
1961 .has_value() &&
1962 identifier ==
1963 *collect_user_data_options_->additional_model_identifier_to_check) {
1964 UpdateCollectUserDataActions();
1965 }
1966 }
1967
OnTouchableAreaChanged(const RectF & visual_viewport,const std::vector<RectF> & touchable_areas,const std::vector<RectF> & restricted_areas)1968 void Controller::OnTouchableAreaChanged(
1969 const RectF& visual_viewport,
1970 const std::vector<RectF>& touchable_areas,
1971 const std::vector<RectF>& restricted_areas) {
1972 for (ControllerObserver& observer : observers_) {
1973 observer.OnTouchableAreaChanged(visual_viewport, touchable_areas,
1974 restricted_areas);
1975 }
1976 }
1977
SetCollectUserDataOptions(CollectUserDataOptions * options)1978 void Controller::SetCollectUserDataOptions(CollectUserDataOptions* options) {
1979 DCHECK(!options ||
1980 (options->confirm_callback && options->additional_actions_callback &&
1981 options->terms_link_callback));
1982
1983 if (collect_user_data_options_ == nullptr && options == nullptr)
1984 return;
1985
1986 collect_user_data_options_ = options;
1987 UpdateCollectUserDataActions();
1988 for (ControllerObserver& observer : observers_) {
1989 observer.OnCollectUserDataOptionsChanged(collect_user_data_options_);
1990 observer.OnUserDataChanged(user_data_.get(), UserData::FieldChange::ALL);
1991 }
1992 }
1993
SetLastSuccessfulUserDataOptions(std::unique_ptr<CollectUserDataOptions> collect_user_data_options)1994 void Controller::SetLastSuccessfulUserDataOptions(
1995 std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
1996 last_collect_user_data_options_ = std::move(collect_user_data_options);
1997 }
1998
GetLastSuccessfulUserDataOptions() const1999 const CollectUserDataOptions* Controller::GetLastSuccessfulUserDataOptions()
2000 const {
2001 return last_collect_user_data_options_.get();
2002 }
2003
WriteUserData(base::OnceCallback<void (UserData *,UserData::FieldChange *)> write_callback)2004 void Controller::WriteUserData(
2005 base::OnceCallback<void(UserData*, UserData::FieldChange*)>
2006 write_callback) {
2007 UserData::FieldChange field_change = UserData::FieldChange::NONE;
2008 std::move(write_callback).Run(user_data_.get(), &field_change);
2009 if (field_change == UserData::FieldChange::NONE) {
2010 return;
2011 }
2012 for (ControllerObserver& observer : observers_) {
2013 observer.OnUserDataChanged(user_data_.get(), field_change);
2014 }
2015 UpdateCollectUserDataActions();
2016 }
2017
StateNeedsUI(AutofillAssistantState state)2018 bool Controller::StateNeedsUI(AutofillAssistantState state) {
2019 if (IsRunningLiteScript()) {
2020 return StateNeedsUiInLiteScript(state);
2021 }
2022 return StateNeedsUiInRegularScript(state, browse_mode_invisible_);
2023 }
2024
IsRunningLiteScript() const2025 bool Controller::IsRunningLiteScript() const {
2026 return service_ ? service_->IsLiteService() : false;
2027 }
2028
OnKeyboardVisibilityChanged(bool visible)2029 void Controller::OnKeyboardVisibilityChanged(bool visible) {
2030 is_keyboard_showing_ = visible;
2031 SetVisibilityAndUpdateUserActions();
2032 }
2033
touchable_element_area()2034 ElementArea* Controller::touchable_element_area() {
2035 if (!touchable_element_area_) {
2036 touchable_element_area_ = std::make_unique<ElementArea>(this);
2037 touchable_element_area_->SetOnUpdate(base::BindRepeating(
2038 &Controller::OnTouchableAreaChanged, weak_ptr_factory_.GetWeakPtr()));
2039 }
2040 return touchable_element_area_.get();
2041 }
2042
script_tracker()2043 ScriptTracker* Controller::script_tracker() {
2044 if (!script_tracker_) {
2045 script_tracker_ = std::make_unique<ScriptTracker>(/* delegate= */ this,
2046 /* listener= */ this);
2047 }
2048 return script_tracker_.get();
2049 }
2050
2051 } // namespace autofill_assistant
2052