// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/assistant/assistant_web_ui_controller.h"
#include "ash/assistant/ui/assistant_web_container_view.h"
#include "ash/assistant/util/deep_link_util.h"
#include "ash/multi_user/multi_user_window_manager_impl.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/memory/raw_ptr.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/events/event_observer.h"
#include "ui/views/event_monitor.h"
namespace ash {
// -----------------------------------------------------------------------------
// AssistantWebContainerEventObserver:
class AssistantWebContainerEventObserver : public ui::EventObserver {
public:
AssistantWebContainerEventObserver(AssistantWebUiController* owner,
views::Widget* widget)
: owner_(owner),
widget_(widget),
event_monitor_(views::EventMonitor::CreateWindowMonitor(
this,
widget->GetNativeWindow(),
{ui::EventType::kKeyPressed})) {}
AssistantWebContainerEventObserver(
const AssistantWebContainerEventObserver&) = delete;
AssistantWebContainerEventObserver& operator=(
const AssistantWebContainerEventObserver&) = delete;
~AssistantWebContainerEventObserver() override = default;
// ui::EventObserver:
void OnEvent(const ui::Event& event) override {
DCHECK(event.type() == ui::EventType::kKeyPressed);
const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
switch (key_event.key_code()) {
case ui::VKEY_BROWSER_BACK:
owner_->OnBackButtonPressed();
break;
case ui::VKEY_W:
if (!key_event.IsControlDown())
break;
event_monitor_.reset();
widget_->Close();
break;
default:
// No action necessary.
break;
}
}
private:
raw_ptr<AssistantWebUiController> owner_ = nullptr;
raw_ptr<views::Widget> widget_ = nullptr;
std::unique_ptr<views::EventMonitor> event_monitor_;
};
// -----------------------------------------------------------------------------
// AssistantWebUiController:
AssistantWebUiController::AssistantWebUiController() {
assistant_controller_observation_.Observe(AssistantController::Get());
}
AssistantWebUiController::~AssistantWebUiController() {
CloseUi();
CHECK(!views::WidgetObserver::IsInObserverList());
}
void AssistantWebUiController::OnWidgetDestroying(views::Widget* widget) {
ResetWebContainerView();
}
void AssistantWebUiController::OnAssistantControllerConstructed() {
AssistantState::Get()->AddObserver(this);
}
void AssistantWebUiController::OnAssistantControllerDestroying() {
AssistantState::Get()->RemoveObserver(this);
}
void AssistantWebUiController::OnDeepLinkReceived(
assistant::util::DeepLinkType type,
const std::map<std::string, std::string>& params) {
if (assistant::util::IsWebDeepLinkType(type, params))
ShowUi(assistant::util::GetWebUrl(type, params).value());
}
void AssistantWebUiController::OnAssistantSettingsEnabled(bool enabled) {
if (!enabled)
CloseUi();
}
void AssistantWebUiController::ShowUi(const GURL& url) {
if (!web_container_view_)
CreateWebContainerView();
web_container_view_->GetWidget()->Show();
web_container_view_->OpenUrl(url);
}
void AssistantWebUiController::CloseUi() {
if (!web_container_view_)
return;
web_container_view_->GetWidget()->CloseNow();
DCHECK_EQ(nullptr, web_container_view_);
}
void AssistantWebUiController::OnBackButtonPressed() {
DCHECK(web_container_view_);
web_container_view_->GoBack();
}
AssistantWebContainerView* AssistantWebUiController::GetViewForTest() {
return web_container_view_;
}
void AssistantWebUiController::CreateWebContainerView() {
DCHECK(!web_container_view_);
web_container_view_ = new AssistantWebContainerView(&view_delegate_);
auto* widget = web_container_view_->GetWidget();
widget->AddObserver(this);
event_observer_ =
std::make_unique<AssistantWebContainerEventObserver>(this, widget);
// Associate the window for Assistant Web UI with the active user in order to
// not leak across user sessions.
auto* window_manager = MultiUserWindowManagerImpl::Get();
if (!window_manager)
return;
const UserSession* active_user_session =
Shell::Get()->session_controller()->GetUserSession(0);
if (!active_user_session)
return;
auto* native_window = widget->GetNativeWindow();
native_window->SetProperty(aura::client::kCreatedByUserGesture, true);
window_manager->SetWindowOwner(native_window,
active_user_session->user_info.account_id);
}
void AssistantWebUiController::ResetWebContainerView() {
DCHECK(web_container_view_);
event_observer_.reset();
web_container_view_->GetWidget()->RemoveObserver(this);
web_container_view_ = nullptr;
}
} // namespace ash