blob: 66b0ef74a2ce368204b14050650bd4ee1e4d0b81 [file] [log] [blame]
David Black71ab74d2018-04-12 06:52:311// Copyright 2018 The Chromium Authors. All rights reserved.
David Blacke8f815042018-03-28 18:59:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
David Black00fdce32018-05-10 20:59:145#include "ash/assistant/assistant_controller.h"
David Blacke8f815042018-03-28 18:59:376
David Blackd72bae462018-04-28 00:47:147#include "ash/assistant/model/assistant_interaction_model_observer.h"
8#include "ash/assistant/model/assistant_ui_element.h"
David Blackf7f8d2012018-04-25 19:48:029#include "ash/assistant/ui/assistant_bubble.h"
David Blacke1a4b9ed2018-04-19 19:55:0810#include "ash/session/session_controller.h"
David Blacke8f815042018-03-28 18:59:3711#include "ash/shell.h"
12#include "ash/shell_delegate.h"
David Blacke1a4b9ed2018-04-19 19:55:0813#include "base/unguessable_token.h"
David Blacke8f815042018-03-28 18:59:3714
15namespace ash {
16
David Black00fdce32018-05-10 20:59:1417AssistantController::AssistantController()
David Blacke8f815042018-03-28 18:59:3718 : assistant_controller_binding_(this),
David Blackf7f8d2012018-04-25 19:48:0219 assistant_event_subscriber_binding_(this),
20 assistant_bubble_(std::make_unique<AssistantBubble>(this)) {
David Black5318ec12018-05-02 01:54:3221 AddInteractionModelObserver(this);
Qiang Xubd6d84e72018-05-09 01:31:5122 Shell::Get()->highlighter_controller()->AddObserver(this);
David Black71ab74d2018-04-12 06:52:3123}
David Blacke8f815042018-03-28 18:59:3724
David Black00fdce32018-05-10 20:59:1425AssistantController::~AssistantController() {
Qiang Xubd6d84e72018-05-09 01:31:5126 Shell::Get()->highlighter_controller()->RemoveObserver(this);
David Black5318ec12018-05-02 01:54:3227 RemoveInteractionModelObserver(this);
28
David Blacke8f815042018-03-28 18:59:3729 assistant_controller_binding_.Close();
30 assistant_event_subscriber_binding_.Close();
David Blacke8f815042018-03-28 18:59:3731}
32
David Black00fdce32018-05-10 20:59:1433void AssistantController::BindRequest(
34 mojom::AssistantControllerRequest request) {
David Blacke8f815042018-03-28 18:59:3735 assistant_controller_binding_.Bind(std::move(request));
36}
37
David Black00fdce32018-05-10 20:59:1438void AssistantController::SetAssistant(
David Blacke8f815042018-03-28 18:59:3739 chromeos::assistant::mojom::AssistantPtr assistant) {
David Black4c3656c2018-04-19 17:31:4740 assistant_ = std::move(assistant);
41
David Blacke8f815042018-03-28 18:59:3742 // Subscribe to Assistant events.
43 chromeos::assistant::mojom::AssistantEventSubscriberPtr ptr;
44 assistant_event_subscriber_binding_.Bind(mojo::MakeRequest(&ptr));
David Black4c3656c2018-04-19 17:31:4745 assistant_->AddAssistantEventSubscriber(std::move(ptr));
46}
47
David Black00fdce32018-05-10 20:59:1448void AssistantController::SetAssistantCardRenderer(
David Blacke1a4b9ed2018-04-19 19:55:0849 mojom::AssistantCardRendererPtr assistant_card_renderer) {
50 assistant_card_renderer_ = std::move(assistant_card_renderer);
51}
52
David Black00fdce32018-05-10 20:59:1453void AssistantController::RenderCard(
David Blacke1a4b9ed2018-04-19 19:55:0854 const base::UnguessableToken& id_token,
55 mojom::AssistantCardParamsPtr params,
56 mojom::AssistantCardRenderer::RenderCallback callback) {
57 DCHECK(assistant_card_renderer_);
58
59 const mojom::UserSession* user_session =
60 Shell::Get()->session_controller()->GetUserSession(0);
61
62 if (!user_session) {
63 LOG(WARNING) << "Unable to retrieve active user session.";
64 return;
65 }
66
67 AccountId account_id = user_session->user_info->account_id;
68
69 assistant_card_renderer_->Render(account_id, id_token, std::move(params),
70 std::move(callback));
71}
72
David Black00fdce32018-05-10 20:59:1473void AssistantController::ReleaseCard(const base::UnguessableToken& id_token) {
David Blacke1a4b9ed2018-04-19 19:55:0874 DCHECK(assistant_card_renderer_);
75 assistant_card_renderer_->Release(id_token);
76}
77
David Black00fdce32018-05-10 20:59:1478void AssistantController::ReleaseCards(
David Black3bfd968602018-04-24 22:07:4679 const std::vector<base::UnguessableToken>& id_tokens) {
80 DCHECK(assistant_card_renderer_);
81 assistant_card_renderer_->ReleaseAll(id_tokens);
82}
83
David Black00fdce32018-05-10 20:59:1484void AssistantController::AddInteractionModelObserver(
David Blackd72bae462018-04-28 00:47:1485 AssistantInteractionModelObserver* observer) {
David Black4c3656c2018-04-19 17:31:4786 assistant_interaction_model_.AddObserver(observer);
87}
88
David Black00fdce32018-05-10 20:59:1489void AssistantController::RemoveInteractionModelObserver(
David Blackd72bae462018-04-28 00:47:1490 AssistantInteractionModelObserver* observer) {
David Black4c3656c2018-04-19 17:31:4791 assistant_interaction_model_.RemoveObserver(observer);
David Blacke8f815042018-03-28 18:59:3792}
93
David Black00fdce32018-05-10 20:59:1494void AssistantController::StartInteraction() {
David Black990b0ac2018-05-01 18:08:0895 // TODO(dmblack): Instruct underlying service to start listening if current
David Black5318ec12018-05-02 01:54:3296 // input modality is VOICE.
97 if (assistant_interaction_model_.interaction_state() ==
98 InteractionState::kInactive) {
David Black990b0ac2018-05-01 18:08:0899 OnInteractionStarted();
David Black5318ec12018-05-02 01:54:32100 }
David Black990b0ac2018-05-01 18:08:08101}
102
David Black00fdce32018-05-10 20:59:14103void AssistantController::StopInteraction() {
David Black5318ec12018-05-02 01:54:32104 if (assistant_interaction_model_.interaction_state() !=
105 InteractionState::kInactive) {
David Black990b0ac2018-05-01 18:08:08106 OnInteractionDismissed();
David Black5318ec12018-05-02 01:54:32107 }
David Black990b0ac2018-05-01 18:08:08108}
109
David Black00fdce32018-05-10 20:59:14110void AssistantController::ToggleInteraction() {
David Black5318ec12018-05-02 01:54:32111 if (assistant_interaction_model_.interaction_state() ==
112 InteractionState::kInactive) {
David Black990b0ac2018-05-01 18:08:08113 StartInteraction();
David Black5318ec12018-05-02 01:54:32114 } else {
David Black990b0ac2018-05-01 18:08:08115 StopInteraction();
David Black5318ec12018-05-02 01:54:32116 }
117}
118
David Black00fdce32018-05-10 20:59:14119void AssistantController::OnInteractionStateChanged(
David Black5318ec12018-05-02 01:54:32120 InteractionState interaction_state) {
David Black873ec7552018-05-05 00:16:27121 if (interaction_state == InteractionState::kInactive) {
David Black5318ec12018-05-02 01:54:32122 assistant_interaction_model_.ClearInteraction();
David Black873ec7552018-05-05 00:16:27123
124 // TODO(dmblack): Input modality should default back to the user's
125 // preferred input modality.
126 assistant_interaction_model_.SetInputModality(InputModality::kVoice);
127 }
David Black990b0ac2018-05-01 18:08:08128}
129
David Black00fdce32018-05-10 20:59:14130void AssistantController::OnHighlighterEnabledChanged(bool enabled) {
Qiang Xubd6d84e72018-05-09 01:31:51131 // TODO(warx): add a reason enum to distinguish the case of deselecting the
132 // tool and done with a stylus selection.
Qiang Xubd6d84e72018-05-09 01:31:51133 assistant_interaction_model_.SetInputModality(InputModality::kStylus);
134 assistant_interaction_model_.SetInteractionState(
135 enabled ? InteractionState::kActive : InteractionState::kInactive);
136}
137
David Black00fdce32018-05-10 20:59:14138void AssistantController::OnInteractionStarted() {
David Black5318ec12018-05-02 01:54:32139 assistant_interaction_model_.SetInteractionState(InteractionState::kActive);
David Black4d28a352018-04-15 22:00:14140}
141
David Black00fdce32018-05-10 20:59:14142void AssistantController::OnInteractionFinished(
143 chromeos::assistant::mojom::AssistantInteractionResolution resolution) {}
David Blackf7f8d2012018-04-25 19:48:02144
David Black00fdce32018-05-10 20:59:14145void AssistantController::OnInteractionDismissed() {
David Black5318ec12018-05-02 01:54:32146 assistant_interaction_model_.SetInteractionState(InteractionState::kInactive);
David Black1d7c2032018-05-09 18:01:02147
148 // When the user-facing interaction is dismissed, we instruct the service to
149 // terminate any listening, speaking, or query in flight.
150 DCHECK(assistant_);
151 assistant_->StopActiveInteraction();
David Black4d28a352018-04-15 22:00:14152}
153
David Black00fdce32018-05-10 20:59:14154void AssistantController::OnDialogPlateContentsChanged(
David Blackb2df49c2018-05-03 23:52:36155 const std::string& text) {
David Black873ec7552018-05-05 00:16:27156 if (text.empty()) {
157 // Note: This does not open the mic. It only updates the input modality to
158 // voice so that we will show the mic icon in the UI.
159 assistant_interaction_model_.SetInputModality(InputModality::kVoice);
160 } else {
David Black1d7c2032018-05-09 18:01:02161 // If switching to keyboard modality from voice, we instruct the service to
162 // terminate any listening, speaking, or query in flight.
163 // TODO(dmblack): We probably want this same logic when switching to any
164 // modality from voice. Handle this instead in OnInputModalityChanged, but
165 // we will need to add a previous modality parameter to that API.
166 if (assistant_interaction_model_.input_modality() ==
167 InputModality::kVoice) {
168 DCHECK(assistant_);
169 assistant_->StopActiveInteraction();
170 }
David Black873ec7552018-05-05 00:16:27171 assistant_interaction_model_.SetInputModality(InputModality::kKeyboard);
172 assistant_interaction_model_.SetMicState(MicState::kClosed);
173 }
David Blackb2df49c2018-05-03 23:52:36174}
175
David Black00fdce32018-05-10 20:59:14176void AssistantController::OnDialogPlateContentsCommitted(
David Blackb2df49c2018-05-03 23:52:36177 const std::string& text) {
178 Query query;
179 query.high_confidence_text = text;
180
181 assistant_interaction_model_.ClearInteraction();
182 assistant_interaction_model_.SetQuery(query);
183
David Black873ec7552018-05-05 00:16:27184 // Note: This does not open the mic. It only updates the input modality to
185 // voice so that we will show the mic icon in the UI.
186 assistant_interaction_model_.SetInputModality(InputModality::kVoice);
187
David Blackb2df49c2018-05-03 23:52:36188 DCHECK(assistant_);
189 assistant_->SendTextQuery(text);
190}
191
David Black00fdce32018-05-10 20:59:14192void AssistantController::OnHtmlResponse(const std::string& response) {
David Black3bfd968602018-04-24 22:07:46193 assistant_interaction_model_.AddUiElement(
David Blackd72bae462018-04-28 00:47:14194 std::make_unique<AssistantCardElement>(response));
David Blacke8f815042018-03-28 18:59:37195}
196
David Black00fdce32018-05-10 20:59:14197void AssistantController::OnSuggestionChipPressed(const std::string& text) {
David Blackd72bae462018-04-28 00:47:14198 Query query;
David Black4c3656c2018-04-19 17:31:47199 query.high_confidence_text = text;
200
201 assistant_interaction_model_.ClearInteraction();
202 assistant_interaction_model_.SetQuery(query);
203
204 DCHECK(assistant_);
205 assistant_->SendTextQuery(text);
206}
207
David Black00fdce32018-05-10 20:59:14208void AssistantController::OnSuggestionsResponse(
David Black46ad4b72018-04-03 00:34:02209 const std::vector<std::string>& response) {
David Black71ab74d2018-04-12 06:52:31210 assistant_interaction_model_.AddSuggestions(response);
David Black46ad4b72018-04-03 00:34:02211}
212
David Black00fdce32018-05-10 20:59:14213void AssistantController::OnTextResponse(const std::string& response) {
David Black3bfd968602018-04-24 22:07:46214 assistant_interaction_model_.AddUiElement(
David Blackd72bae462018-04-28 00:47:14215 std::make_unique<AssistantTextElement>(response));
David Blacke8f815042018-03-28 18:59:37216}
217
David Black00fdce32018-05-10 20:59:14218void AssistantController::OnSpeechRecognitionStarted() {
David Black71ab74d2018-04-12 06:52:31219 assistant_interaction_model_.ClearInteraction();
David Black873ec7552018-05-05 00:16:27220 assistant_interaction_model_.SetInputModality(InputModality::kVoice);
221 assistant_interaction_model_.SetMicState(MicState::kOpen);
David Black89ac6f82018-04-03 17:38:12222}
223
David Black00fdce32018-05-10 20:59:14224void AssistantController::OnSpeechRecognitionIntermediateResult(
David Black89ac6f82018-04-03 17:38:12225 const std::string& high_confidence_text,
226 const std::string& low_confidence_text) {
David Black4c3656c2018-04-19 17:31:47227 assistant_interaction_model_.SetQuery(
228 {high_confidence_text, low_confidence_text});
David Black89ac6f82018-04-03 17:38:12229}
230
David Black00fdce32018-05-10 20:59:14231void AssistantController::OnSpeechRecognitionEndOfUtterance() {
David Black873ec7552018-05-05 00:16:27232 assistant_interaction_model_.SetMicState(MicState::kClosed);
David Black89ac6f82018-04-03 17:38:12233}
234
David Black00fdce32018-05-10 20:59:14235void AssistantController::OnSpeechRecognitionFinalResult(
David Black89ac6f82018-04-03 17:38:12236 const std::string& final_result) {
David Blackd72bae462018-04-28 00:47:14237 Query query;
David Black4c3656c2018-04-19 17:31:47238 query.high_confidence_text = final_result;
239 assistant_interaction_model_.SetQuery(query);
David Black89ac6f82018-04-03 17:38:12240}
241
David Black00fdce32018-05-10 20:59:14242void AssistantController::OnSpeechLevelUpdated(float speech_level) {
Alan Lau7bd29ced2018-03-29 18:39:51243 // TODO(dmblack): Handle.
244 NOTIMPLEMENTED();
245}
246
David Black00fdce32018-05-10 20:59:14247void AssistantController::OnOpenUrlResponse(const GURL& url) {
David Blacke8f815042018-03-28 18:59:37248 Shell::Get()->shell_delegate()->OpenUrlFromArc(url);
David Black990b0ac2018-05-01 18:08:08249 StopInteraction();
David Blacke8f815042018-03-28 18:59:37250}
251
David Blacke8f815042018-03-28 18:59:37252} // namespace ash