blob: 44154f1639b78c5d7fbd7c7a5a7cdc41824c5f6b [file] [log] [blame]
// Copyright 2020 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/quick_answers/quick_answers_ui_controller.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
#include "ash/public/cpp/new_window_delegate.h"
#include "ash/quick_answers/quick_answers_controller_impl.h"
#include "ash/quick_answers/ui/quick_answers_view.h"
#include "ash/quick_answers/ui/user_consent_view.h"
#include "ash/quick_answers/ui/user_notice_view.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "chromeos/components/quick_answers/quick_answers_model.h"
#include "chromeos/services/assistant/public/cpp/assistant_service.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/escape.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget.h"
using chromeos::quick_answers::QuickAnswer;
namespace ash {
namespace {
constexpr char kGoogleSearchUrlPrefix[] = "https://www.google.com/search?q=";
constexpr char kFeedbackDescriptionTemplate[] = "#QuickAnswers\nQuery:%s\n";
} // namespace
QuickAnswersUiController::QuickAnswersUiController(
QuickAnswersControllerImpl* controller)
: controller_(controller) {}
QuickAnswersUiController::~QuickAnswersUiController() {
quick_answers_view_ = nullptr;
user_notice_view_ = nullptr;
user_consent_view_ = nullptr;
}
void QuickAnswersUiController::CreateQuickAnswersView(const gfx::Rect& bounds,
const std::string& title,
const std::string& query,
bool is_internal) {
// Currently there are timing issues that causes the quick answers view is not
// dismissed. TODO(updowndota): Remove the special handling after the root
// cause is found.
if (quick_answers_view_) {
LOG(ERROR) << "Quick answers view not dismissed.";
CloseQuickAnswersView();
}
DCHECK(!user_notice_view_);
DCHECK(!user_consent_view_);
SetActiveQuery(query);
quick_answers_view_ = new QuickAnswersView(bounds, title, is_internal, this);
quick_answers_view_->GetWidget()->ShowInactive();
}
void QuickAnswersUiController::OnQuickAnswersViewPressed() {
// Route dismissal through |controller_| for logging impressions.
controller_->DismissQuickAnswers(/*is_active=*/true);
if (chromeos::features::IsQuickAnswersV2Enabled()) {
NewWindowDelegate::GetInstance()->NewTabWithUrl(
GURL(kGoogleSearchUrlPrefix +
net::EscapeUrlEncodedData(query_, /*use_plus=*/true)),
/*from_user_interaction=*/true);
} else {
ash::AssistantInteractionController::Get()->StartTextInteraction(
query_, /*allow_tts=*/false,
chromeos::assistant::AssistantQuerySource::kQuickAnswers);
}
controller_->OnQuickAnswerClick();
}
bool QuickAnswersUiController::CloseQuickAnswersView() {
if (quick_answers_view_) {
quick_answers_view_->GetWidget()->Close();
quick_answers_view_ = nullptr;
return true;
}
return false;
}
void QuickAnswersUiController::OnRetryLabelPressed() {
controller_->OnRetryQuickAnswersRequest();
}
void QuickAnswersUiController::RenderQuickAnswersViewWithResult(
const gfx::Rect& anchor_bounds,
const QuickAnswer& quick_answer) {
if (!quick_answers_view_)
return;
// QuickAnswersView was initiated with a loading page and will be updated
// when quick answers result from server side is ready.
quick_answers_view_->UpdateView(anchor_bounds, quick_answer);
}
void QuickAnswersUiController::SetActiveQuery(const std::string& query) {
query_ = query;
}
void QuickAnswersUiController::ShowRetry() {
if (!quick_answers_view_)
return;
quick_answers_view_->ShowRetryView();
}
void QuickAnswersUiController::UpdateQuickAnswersBounds(
const gfx::Rect& anchor_bounds) {
if (quick_answers_view_)
quick_answers_view_->UpdateAnchorViewBounds(anchor_bounds);
if (user_notice_view_)
user_notice_view_->UpdateAnchorViewBounds(anchor_bounds);
}
void QuickAnswersUiController::CreateUserNoticeView(
const gfx::Rect& anchor_bounds,
const std::u16string& intent_type,
const std::u16string& intent_text) {
DCHECK(!quick_answers_view_);
DCHECK(!user_notice_view_);
DCHECK(!user_consent_view_);
user_notice_view_ = new quick_answers::UserNoticeView(
anchor_bounds, intent_type, intent_text, this);
user_notice_view_->GetWidget()->ShowInactive();
}
void QuickAnswersUiController::CloseUserNoticeView() {
if (user_notice_view_) {
user_notice_view_->GetWidget()->Close();
user_notice_view_ = nullptr;
}
}
void QuickAnswersUiController::CreateUserConsentView(
const gfx::Rect& anchor_bounds,
const std::u16string& intent_type,
const std::u16string& intent_text) {
DCHECK(!quick_answers_view_);
DCHECK(!user_notice_view_);
DCHECK(!user_consent_view_);
user_consent_view_ = new quick_answers::UserConsentView(
anchor_bounds, intent_type, intent_text, this);
user_consent_view_->GetWidget()->ShowInactive();
}
void QuickAnswersUiController::CloseUserConsentView() {
if (user_consent_view_) {
user_consent_view_->GetWidget()->Close();
user_consent_view_ = nullptr;
}
}
void QuickAnswersUiController::OnAcceptButtonPressed() {
DCHECK(user_notice_view_);
controller_->OnUserNoticeAccepted();
// The Quick-Answer displayed should gain focus if it is created when this
// button is pressed.
if (quick_answers_view_)
quick_answers_view_->RequestFocus();
}
void QuickAnswersUiController::OnManageSettingsButtonPressed() {
controller_->OnNoticeSettingsRequestedByUser();
}
void QuickAnswersUiController::OnDogfoodButtonPressed() {
// Route dismissal through |controller_| for logging impressions.
controller_->DismissQuickAnswers(/*is_active=*/true);
controller_->OpenQuickAnswersDogfoodLink();
}
void QuickAnswersUiController::OnSettingsButtonPressed() {
// Route dismissal through |controller_| for logging impressions.
controller_->DismissQuickAnswers(/*is_active=*/true);
controller_->OpenQuickAnswersSettings();
}
void QuickAnswersUiController::OnReportQueryButtonPressed() {
NewWindowDelegate::GetInstance()->OpenFeedbackPage(
NewWindowDelegate::FeedbackSource::kFeedbackSourceQuickAnswers,
base::StringPrintf(kFeedbackDescriptionTemplate, query_.c_str()));
}
void QuickAnswersUiController::OnUserConsentResult(bool consented) {
DCHECK(user_consent_view_);
controller_->OnUserConsentResult(consented);
if (consented && quick_answers_view_)
quick_answers_view_->RequestFocus();
}
} // namespace ash