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