1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/macros.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "build/buildflag.h"
15 #include "chrome/browser/chromeos/assistant/assistant_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/ui/ash/ash_util.h"
19 #include "chrome/browser/ui/views/chrome_web_dialog_view.h"
20 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
21 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/grit/browser_resources.h"
24 #include "chromeos/assistant/buildflags.h"
25 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
26 #include "chromeos/services/assistant/public/cpp/features.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/session_manager/core/session_manager.h"
29 #include "content/public/browser/host_zoom_map.h"
30 #include "content/public/browser/url_data_source.h"
31 #include "content/public/browser/web_ui.h"
32 #include "content/public/browser/web_ui_data_source.h"
33 #include "content/public/common/content_features.h"
34 #include "net/base/url_util.h"
35 #include "services/network/public/mojom/content_security_policy.mojom.h"
36 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
37 #include "ui/display/display.h"
38 #include "ui/display/screen.h"
39 #include "ui/gfx/geometry/insets.h"
40 #include "ui/views/widget/widget.h"
41 #include "ui/wm/core/window_animations.h"
42
43 namespace chromeos {
44
45 namespace {
46
47 AssistantOptInDialog* g_dialog = nullptr;
48
49 constexpr int kCaptionBarHeight = 32;
50 constexpr int kDialogMargin = 48;
51 constexpr gfx::Size kDialogMaxSize = gfx::Size(768, 768);
52 constexpr gfx::Size kDialogMinSize = gfx::Size(544, 464);
53 constexpr gfx::Insets kDialogInsets =
54 gfx::Insets(kDialogMargin + kCaptionBarHeight,
55 kDialogMargin,
56 kDialogMargin,
57 kDialogMargin);
58
59 constexpr char kFlowTypeParamKey[] = "flow-type";
60 constexpr char kCaptionBarHeightParamKey[] = "caption-bar-height";
61
CreateAssistantOptInURL(ash::FlowType type)62 GURL CreateAssistantOptInURL(ash::FlowType type) {
63 GURL gurl(chrome::kChromeUIAssistantOptInURL);
64 gurl = net::AppendQueryParameter(
65 gurl, kFlowTypeParamKey, base::NumberToString(static_cast<int>(type)));
66 gurl = net::AppendQueryParameter(gurl, kCaptionBarHeightParamKey,
67 base::NumberToString(kCaptionBarHeight));
68 return gurl;
69 }
70
71 } // namespace
72
AssistantOptInUI(content::WebUI * web_ui)73 AssistantOptInUI::AssistantOptInUI(content::WebUI* web_ui)
74 : ui::WebDialogUI(web_ui) {
75 // Set up the chrome://assistant-optin source.
76 content::WebUIDataSource* source =
77 content::WebUIDataSource::Create(chrome::kChromeUIAssistantOptInHost);
78
79 auto assistant_handler =
80 std::make_unique<AssistantOptInFlowScreenHandler>(&js_calls_container_);
81 assistant_handler_ptr_ = assistant_handler.get();
82 web_ui->AddMessageHandler(std::move(assistant_handler));
83 assistant_handler_ptr_->set_on_initialized(base::BindOnce(
84 &AssistantOptInUI::Initialize, weak_factory_.GetWeakPtr()));
85 assistant_handler_ptr_->SetupAssistantConnection();
86
87 base::DictionaryValue localized_strings;
88 assistant_handler_ptr_->GetLocalizedStrings(&localized_strings);
89
90 OobeUI::AddOobeComponents(source, localized_strings);
91
92 source->AddLocalizedStrings(localized_strings);
93 source->UseStringsJs();
94 source->AddResourcePath("assistant_optin.js", IDR_ASSISTANT_OPTIN_JS);
95 source->AddResourcePath("assistant_logo.png", IDR_ASSISTANT_LOGO_PNG);
96 source->SetDefaultResource(IDR_ASSISTANT_OPTIN_HTML);
97 source->AddResourcePath("voice_match_animation.json",
98 IDR_ASSISTANT_VOICE_MATCH_ANIMATION);
99 source->AddResourcePath("voice_match_already_setup_animation.json",
100 IDR_ASSISTANT_VOICE_MATCH_ALREADY_SETUP_ANIMATION);
101 source->OverrideContentSecurityPolicy(
102 network::mojom::CSPDirectiveName::WorkerSrc, "worker-src blob: 'self';");
103 source->DisableTrustedTypesCSP();
104 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
105
106 // Do not zoom for Assistant opt-in web contents.
107 content::HostZoomMap* zoom_map =
108 content::HostZoomMap::GetForWebContents(web_ui->GetWebContents());
109 DCHECK(zoom_map);
110 zoom_map->SetZoomLevelForHost(web_ui->GetWebContents()->GetURL().host(), 0);
111 }
112
113 AssistantOptInUI::~AssistantOptInUI() = default;
114
OnDialogClosed()115 void AssistantOptInUI::OnDialogClosed() {
116 if (assistant_handler_ptr_) {
117 assistant_handler_ptr_->OnDialogClosed();
118 }
119 }
120
Initialize()121 void AssistantOptInUI::Initialize() {
122 js_calls_container_.ExecuteDeferredJSCalls(web_ui());
123 }
124
125 // AssistantOptInDialog
126
127 // static
Show(ash::FlowType type,ash::AssistantSetup::StartAssistantOptInFlowCallback callback)128 void AssistantOptInDialog::Show(
129 ash::FlowType type,
130 ash::AssistantSetup::StartAssistantOptInFlowCallback callback) {
131 #if !BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
132 std::move(callback).Run(false);
133 #else
134 // Check Assistant allowed state.
135 if (::assistant::IsAssistantAllowedForProfile(
136 ProfileManager::GetActiveUserProfile()) !=
137 chromeos::assistant::AssistantAllowedState::ALLOWED) {
138 std::move(callback).Run(false);
139 return;
140 }
141
142 // Check session state here to prevent timing issue -- session state might
143 // have changed during the mojom calls to launch the opt-in dalog.
144 if (session_manager::SessionManager::Get()->session_state() !=
145 session_manager::SessionState::ACTIVE) {
146 std::move(callback).Run(false);
147 return;
148 }
149 if (g_dialog) {
150 g_dialog->Focus();
151 std::move(callback).Run(false);
152 return;
153 }
154 g_dialog = new AssistantOptInDialog(type, std::move(callback));
155
156 g_dialog->ShowSystemDialog();
157 #endif
158 }
159
160 // static
BounceIfActive()161 bool AssistantOptInDialog::BounceIfActive() {
162 if (!g_dialog)
163 return false;
164
165 g_dialog->Focus();
166 wm::AnimateWindow(g_dialog->dialog_window(),
167 wm::WINDOW_ANIMATION_TYPE_BOUNCE);
168 return true;
169 }
170
AssistantOptInDialog(ash::FlowType type,ash::AssistantSetup::StartAssistantOptInFlowCallback callback)171 AssistantOptInDialog::AssistantOptInDialog(
172 ash::FlowType type,
173 ash::AssistantSetup::StartAssistantOptInFlowCallback callback)
174 : SystemWebDialogDelegate(CreateAssistantOptInURL(type), base::string16()),
175 callback_(std::move(callback)) {}
176
~AssistantOptInDialog()177 AssistantOptInDialog::~AssistantOptInDialog() {
178 DCHECK_EQ(this, g_dialog);
179 g_dialog = nullptr;
180 }
181
AdjustWidgetInitParams(views::Widget::InitParams * params)182 void AssistantOptInDialog::AdjustWidgetInitParams(
183 views::Widget::InitParams* params) {
184 params->z_order = ui::ZOrderLevel::kNormal;
185 }
186
GetDialogSize(gfx::Size * size) const187 void AssistantOptInDialog::GetDialogSize(gfx::Size* size) const {
188 auto bounds = display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
189 bounds.Inset(kDialogInsets);
190 auto dialog_size = bounds.size();
191 dialog_size.SetToMin(kDialogMaxSize);
192 dialog_size.SetToMax(kDialogMinSize);
193 size->SetSize(dialog_size.width(), dialog_size.height());
194 }
195
GetDialogArgs() const196 std::string AssistantOptInDialog::GetDialogArgs() const {
197 return std::string();
198 }
199
OnDialogShown(content::WebUI * webui)200 void AssistantOptInDialog::OnDialogShown(content::WebUI* webui) {
201 assistant_ui_ = static_cast<AssistantOptInUI*>(webui->GetController());
202 }
203
OnDialogClosed(const std::string & json_retval)204 void AssistantOptInDialog::OnDialogClosed(const std::string& json_retval) {
205 if (assistant_ui_)
206 assistant_ui_->OnDialogClosed();
207
208 PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
209 const bool completed =
210 prefs->GetBoolean(chromeos::assistant::prefs::kAssistantEnabled) &&
211 (prefs->GetInteger(assistant::prefs::kAssistantConsentStatus) ==
212 assistant::prefs::ConsentStatus::kActivityControlAccepted);
213 std::move(callback_).Run(completed);
214 SystemWebDialogDelegate::OnDialogClosed(json_retval);
215 }
216
217 } // namespace chromeos
218