|  | // Copyright 2019 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/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 "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::ET_KEY_PRESSED})) {} | 
|  |  | 
|  | 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::ET_KEY_PRESSED); | 
|  |  | 
|  | 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: | 
|  | AssistantWebUiController* owner_ = nullptr; | 
|  | 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 |