blob: 19c4df215b339b7d1735efc6a0686c40dd705bc1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/assistant/model/assistant_response.h"
#include "ash/assistant/model/assistant_ui_element.h"
#include "base/bind.h"
namespace ash {
// AssistantResponse -----------------------------------------------------------
AssistantResponse::AssistantResponse() = default;
AssistantResponse::~AssistantResponse() = default;
void AssistantResponse::AddUiElement(
std::unique_ptr<AssistantUiElement> ui_element) {
ui_elements_.push_back(std::move(ui_element));
}
const std::vector<std::unique_ptr<AssistantUiElement>>&
AssistantResponse::GetUiElements() const {
return ui_elements_;
}
void AssistantResponse::AddSuggestions(
std::vector<AssistantSuggestionPtr> suggestions) {
for (AssistantSuggestionPtr& suggestion : suggestions)
suggestions_.push_back(std::move(suggestion));
}
const chromeos::assistant::mojom::AssistantSuggestion*
AssistantResponse::GetSuggestionById(int id) const {
// We consider the index of a suggestion within our backing vector to be its
// unique identifier.
DCHECK_GE(id, 0);
DCHECK_LT(id, static_cast<int>(suggestions_.size()));
return suggestions_.at(id).get();
}
std::map<int, const chromeos::assistant::mojom::AssistantSuggestion*>
AssistantResponse::GetSuggestions() const {
std::map<int, const AssistantSuggestion*> suggestions;
// We use index within our backing vector to represent the unique identifier
// for a suggestion.
int id = 0;
for (const AssistantSuggestionPtr& suggestion : suggestions_)
suggestions[id++] = suggestion.get();
return suggestions;
}
void AssistantResponse::Process(
mojo::Remote<content::mojom::NavigableContentsFactory> contents_factory,
ProcessingCallback callback) {
processor_ = std::make_unique<Processor>(*this, std::move(contents_factory),
std::move(callback));
processor_->Process();
}
// AssistantResponse::Processor ------------------------------------------------
AssistantResponse::Processor::Processor(
AssistantResponse& response,
mojo::Remote<content::mojom::NavigableContentsFactory> contents_factory,
ProcessingCallback callback)
: response_(response),
contents_factory_(std::move(contents_factory)),
callback_(std::move(callback)) {}
AssistantResponse::Processor::~Processor() {
if (callback_)
std::move(callback_).Run(/*success=*/false);
}
void AssistantResponse::Processor::Process() {
// Responses should only be processed once.
DCHECK_EQ(ProcessingState::kUnprocessed, response_.processing_state());
response_.set_processing_state(ProcessingState::kProcessing);
for (const auto& ui_element : response_.GetUiElements()) {
switch (ui_element->GetType()) {
case AssistantUiElementType::kCard:
++processing_count_;
// Start asynchronous processing of the card element.
static_cast<AssistantCardElement*>(ui_element.get())
->Process(contents_factory_.get(),
base::BindOnce(
&AssistantResponse::Processor::OnFinishedProcessing,
base::Unretained(this)));
break;
case AssistantUiElementType::kText:
// No processing necessary.
break;
}
}
// If any elements are processing asynchronously this will no-op.
TryFinishing();
}
void AssistantResponse::Processor::OnFinishedProcessing(bool success) {
// We handle success/failure cases the same because failures will skipped in
// view handling. We decrement our |processing_count_| and attempt to finish
// response processing. This will no-op if elements are still processing.
--processing_count_;
TryFinishing();
}
void AssistantResponse::Processor::TryFinishing() {
// No-op if we are already finished or if elements are still processing.
if (!callback_ || processing_count_ > 0)
return;
// Notify processing success.
response_.set_processing_state(ProcessingState::kProcessed);
std::move(callback_).Run(/*success=*/true);
}
} // namespace ash