cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / browser / ui / webui / media_router / media_router_webui_message_handler.cc
blob087034a8f3165ff1b49429d8d156c647166a4f4c
1 // Copyright 2015 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.
5 #include "chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
12 #include "extensions/common/constants.h"
14 namespace media_router {
16 namespace {
18 const char kHelpPageUrlPrefix[] =
19 "https://support.google.com/chromecast/answer/%d";
21 // Message names.
22 const char kRequestInitialData[] = "requestInitialData";
23 const char kCreateRoute[] = "requestRoute";
24 const char kActOnIssue[] = "actOnIssue";
25 const char kCloseRoute[] = "closeRoute";
26 const char kCloseDialog[] = "closeDialog";
28 // JS function names.
29 const char kSetInitialData[] = "media_router.ui.setInitialData";
30 const char kOnCreateRouteResponseReceived[] =
31 "media_router.ui.onCreateRouteResponseReceived";
32 const char kSetIssue[] = "media_router.ui.setIssue";
33 const char kSetSinkList[] = "media_router.ui.setSinkList";
34 const char kSetRouteList[] = "media_router.ui.setRouteList";
35 const char kSetCastModeList[] = "media_router.ui.setCastModeList";
36 const char kWindowOpen[] = "window.open";
38 scoped_ptr<base::ListValue> SinksToValue(
39 const std::vector<MediaSinkWithCastModes>& sinks) {
40 scoped_ptr<base::ListValue> value(new base::ListValue);
42 for (const MediaSinkWithCastModes& sink_with_cast_modes : sinks) {
43 scoped_ptr<base::DictionaryValue> sink_val(new base::DictionaryValue);
45 const MediaSink& sink = sink_with_cast_modes.sink;
46 sink_val->SetString("id", sink.id());
47 sink_val->SetString("name", sink.name());
48 sink_val->SetInteger("iconType", sink.icon_type());
49 sink_val->SetBoolean("isLaunching", sink.is_launching());
51 scoped_ptr<base::ListValue> cast_modes_val(new base::ListValue);
52 for (MediaCastMode cast_mode : sink_with_cast_modes.cast_modes)
53 cast_modes_val->AppendInteger(cast_mode);
54 sink_val->Set("castModes", cast_modes_val.Pass());
56 value->Append(sink_val.release());
59 return value.Pass();
62 scoped_ptr<base::DictionaryValue> RouteToValue(
63 const MediaRoute& route, const std::string& extension_id) {
64 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
66 dictionary->SetString("id", route.media_route_id());
67 dictionary->SetString("sinkId", route.media_sink_id());
68 dictionary->SetString("description", route.description());
69 dictionary->SetBoolean("isLocal", route.is_local());
71 const std::string& custom_path = route.custom_controller_path();
73 if (!custom_path.empty()) {
74 std::string full_custom_controller_path = base::StringPrintf("%s://%s/%s",
75 extensions::kExtensionScheme, extension_id.c_str(),
76 custom_path.c_str());
77 DCHECK(GURL(full_custom_controller_path).is_valid());
78 dictionary->SetString("customControllerPath",
79 full_custom_controller_path);
82 return dictionary.Pass();
85 scoped_ptr<base::ListValue> RoutesToValue(
86 const std::vector<MediaRoute>& routes, const std::string& extension_id) {
87 scoped_ptr<base::ListValue> value(new base::ListValue);
89 for (const MediaRoute& route : routes) {
90 scoped_ptr<base::DictionaryValue> route_val(RouteToValue(route,
91 extension_id));
92 value->Append(route_val.release());
95 return value.Pass();
98 scoped_ptr<base::ListValue> CastModesToValue(const CastModeSet& cast_modes,
99 const std::string& source_host) {
100 scoped_ptr<base::ListValue> value(new base::ListValue);
102 for (const MediaCastMode& cast_mode : cast_modes) {
103 scoped_ptr<base::DictionaryValue> cast_mode_val(new base::DictionaryValue);
104 cast_mode_val->SetInteger("type", cast_mode);
105 cast_mode_val->SetString(
106 "description", MediaCastModeToDescription(cast_mode, source_host));
107 cast_mode_val->SetString("host", source_host);
108 value->Append(cast_mode_val.release());
111 return value.Pass();
114 // Returns an Issue dictionary created from |issue| that can be used in WebUI.
115 scoped_ptr<base::DictionaryValue> IssueToValue(const Issue& issue) {
116 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
117 dictionary->SetString("id", issue.id());
118 dictionary->SetString("title", issue.title());
119 dictionary->SetString("message", issue.message());
120 dictionary->SetInteger("defaultActionType", issue.default_action().type());
121 if (!issue.secondary_actions().empty()) {
122 dictionary->SetInteger("secondaryActionType",
123 issue.secondary_actions().begin()->type());
125 if (!issue.route_id().empty())
126 dictionary->SetString("routeId", issue.route_id());
127 dictionary->SetBoolean("isBlocking", issue.is_blocking());
129 return dictionary.Pass();
132 bool IsValidIssueActionTypeNum(int issue_action_type_num) {
133 return issue_action_type_num >= 0 &&
134 issue_action_type_num < IssueAction::TYPE_MAX;
137 // Composes a "learn more" URL. The URL depends on template arguments in |args|.
138 // Returns an empty string if |args| is invalid.
139 std::string GetLearnMoreUrl(const base::DictionaryValue* args) {
140 // TODO(imcheng): The template arguments for determining the learn more URL
141 // should come from the Issue object in the browser, not from WebUI.
142 int help_page_id = -1;
143 if (!args->GetInteger("helpPageId", &help_page_id) || help_page_id < 0) {
144 DVLOG(1) << "Invalid help page id.";
145 return std::string();
148 std::string help_url = base::StringPrintf(kHelpPageUrlPrefix, help_page_id);
149 if (!GURL(help_url).is_valid()) {
150 DVLOG(1) << "Error: URL is invalid and cannot be opened.";
151 return std::string();
153 return help_url;
156 } // namespace
158 MediaRouterWebUIMessageHandler::MediaRouterWebUIMessageHandler(
159 MediaRouterUI* media_router_ui)
160 : dialog_closing_(false),
161 media_router_ui_(media_router_ui) {
162 DCHECK(media_router_ui_);
165 MediaRouterWebUIMessageHandler::~MediaRouterWebUIMessageHandler() {
168 void MediaRouterWebUIMessageHandler::UpdateSinks(
169 const std::vector<MediaSinkWithCastModes>& sinks) {
170 DVLOG(2) << "UpdateSinks";
171 scoped_ptr<base::ListValue> sinks_val(SinksToValue(sinks));
172 web_ui()->CallJavascriptFunction(kSetSinkList, *sinks_val);
175 void MediaRouterWebUIMessageHandler::UpdateRoutes(
176 const std::vector<MediaRoute>& routes) {
177 DVLOG(2) << "UpdateRoutes";
178 scoped_ptr<base::ListValue> routes_val(RoutesToValue(routes,
179 media_router_ui_->GetRouteProviderExtensionId()));
180 web_ui()->CallJavascriptFunction(kSetRouteList, *routes_val);
183 void MediaRouterWebUIMessageHandler::UpdateCastModes(
184 const CastModeSet& cast_modes,
185 const std::string& source_host) {
186 DVLOG(2) << "UpdateCastModes";
187 scoped_ptr<base::ListValue> cast_modes_val(
188 CastModesToValue(cast_modes, source_host));
189 web_ui()->CallJavascriptFunction(kSetCastModeList, *cast_modes_val);
192 void MediaRouterWebUIMessageHandler::OnCreateRouteResponseReceived(
193 const MediaSink::Id& sink_id,
194 const MediaRoute* route) {
195 DVLOG(2) << "OnCreateRouteResponseReceived";
196 if (route) {
197 scoped_ptr<base::DictionaryValue> route_value(RouteToValue(*route,
198 media_router_ui_->GetRouteProviderExtensionId()));
199 web_ui()->CallJavascriptFunction(kOnCreateRouteResponseReceived,
200 base::StringValue(sink_id), *route_value);
201 } else {
202 web_ui()->CallJavascriptFunction(kOnCreateRouteResponseReceived,
203 base::StringValue(sink_id),
204 *base::Value::CreateNullValue());
208 void MediaRouterWebUIMessageHandler::UpdateIssue(const Issue* issue) {
209 DVLOG(2) << "UpdateIssue";
210 if (issue) {
211 scoped_ptr<base::DictionaryValue> issue_val(IssueToValue(*issue));
212 web_ui()->CallJavascriptFunction(kSetIssue, *issue_val);
213 } else {
214 // Clears the issue in the WebUI.
215 web_ui()->CallJavascriptFunction(kSetIssue);
219 void MediaRouterWebUIMessageHandler::RegisterMessages() {
220 web_ui()->RegisterMessageCallback(
221 kRequestInitialData,
222 base::Bind(&MediaRouterWebUIMessageHandler::OnRequestInitialData,
223 base::Unretained(this)));
224 web_ui()->RegisterMessageCallback(
225 kCreateRoute,
226 base::Bind(&MediaRouterWebUIMessageHandler::OnCreateRoute,
227 base::Unretained(this)));
228 web_ui()->RegisterMessageCallback(
229 kActOnIssue,
230 base::Bind(&MediaRouterWebUIMessageHandler::OnActOnIssue,
231 base::Unretained(this)));
232 web_ui()->RegisterMessageCallback(
233 kCloseRoute,
234 base::Bind(&MediaRouterWebUIMessageHandler::OnCloseRoute,
235 base::Unretained(this)));
236 web_ui()->RegisterMessageCallback(
237 kCloseDialog,
238 base::Bind(&MediaRouterWebUIMessageHandler::OnCloseDialog,
239 base::Unretained(this)));
242 void MediaRouterWebUIMessageHandler::OnRequestInitialData(
243 const base::ListValue* args) {
244 DVLOG(1) << "OnRequestInitialData";
245 base::DictionaryValue initial_data;
247 initial_data.SetString("headerText",
248 media_router_ui_->GetInitialHeaderText());
249 initial_data.SetString("headerTextTooltip",
250 media_router_ui_->GetInitialHeaderTextTooltip());
252 // "No Cast devices found?" Chromecast help center page.
253 initial_data.SetString("deviceMissingUrl",
254 base::StringPrintf(kHelpPageUrlPrefix, 3249268));
256 scoped_ptr<base::ListValue> sinks(SinksToValue(media_router_ui_->sinks()));
257 initial_data.Set("sinks", sinks.release());
259 scoped_ptr<base::ListValue> routes(RoutesToValue(media_router_ui_->routes(),
260 media_router_ui_->GetRouteProviderExtensionId()));
261 initial_data.Set("routes", routes.release());
263 scoped_ptr<base::ListValue> cast_modes(CastModesToValue(
264 media_router_ui_->cast_modes(),
265 media_router_ui_->GetFrameURLHost()));
266 initial_data.Set("castModes", cast_modes.release());
268 web_ui()->CallJavascriptFunction(kSetInitialData, initial_data);
269 media_router_ui_->UIInitialized();
272 void MediaRouterWebUIMessageHandler::OnCreateRoute(
273 const base::ListValue* args) {
274 DVLOG(1) << "OnCreateRoute";
275 const base::DictionaryValue* args_dict = nullptr;
276 std::string sink_id;
277 int cast_mode_num = -1;
278 if (!args->GetDictionary(0, &args_dict) ||
279 !args_dict->GetString("sinkId", &sink_id) ||
280 !args_dict->GetInteger("selectedCastMode", &cast_mode_num)) {
281 DVLOG(1) << "Unable to extract args.";
282 return;
285 if (sink_id.empty()) {
286 DVLOG(1) << "Media Route Provider Manager did not respond with a "
287 << "valid sink ID. Aborting.";
288 return;
291 MediaRouterUI* media_router_ui =
292 static_cast<MediaRouterUI*>(web_ui()->GetController());
293 if (media_router_ui->has_pending_route_request()) {
294 DVLOG(1) << "UI already has pending route request. Ignoring.";
295 return;
298 DVLOG(2) << "sink id: " << sink_id << ", cast mode: " << cast_mode_num;
300 // TODO(haibinlu): Pass additional parameters into the CreateRoute request,
301 // e.g. low-fps-mirror, user-override. (crbug.com/490364)
302 bool success = false;
303 if (IsValidCastModeNum(cast_mode_num)) {
304 // User explicitly selected cast mode.
305 DVLOG(2) << "Cast mode override: " << cast_mode_num;
306 success = media_router_ui->CreateRouteWithCastModeOverride(
307 sink_id, static_cast<MediaCastMode>(cast_mode_num));
308 } else {
309 success = media_router_ui->CreateRoute(sink_id);
312 // TODO(imcheng): Display error in UI. (crbug.com/490372)
313 if (!success)
314 DVLOG(1) << "Error initiating route request.";
317 void MediaRouterWebUIMessageHandler::OnActOnIssue(
318 const base::ListValue* args) {
319 DVLOG(1) << "OnActOnIssue";
320 const base::DictionaryValue* args_dict = nullptr;
321 Issue::Id issue_id;
322 int action_type_num = -1;
323 if (!args->GetDictionary(0, &args_dict) ||
324 !args_dict->GetString("issueId", &issue_id) ||
325 !args_dict->GetInteger("actionType", &action_type_num)) {
326 DVLOG(1) << "Unable to extract args.";
327 return;
329 if (!IsValidIssueActionTypeNum(action_type_num)) {
330 DVLOG(1) << "Invalid action type: " << action_type_num;
331 return;
333 IssueAction::Type action_type =
334 static_cast<IssueAction::Type>(action_type_num);
335 if (ActOnIssueType(action_type, args_dict))
336 DVLOG(1) << "ActOnIssueType failed for Issue ID " << issue_id;
337 media_router_ui_->ClearIssue(issue_id);
340 void MediaRouterWebUIMessageHandler::OnCloseRoute(
341 const base::ListValue* args) {
342 DVLOG(1) << "OnCloseRoute";
343 const base::DictionaryValue* args_dict = nullptr;
344 std::string route_id;
345 if (!args->GetDictionary(0, &args_dict) ||
346 !args_dict->GetString("routeId", &route_id)) {
347 DVLOG(1) << "Unable to extract args.";
348 return;
350 media_router_ui_->CloseRoute(route_id);
353 void MediaRouterWebUIMessageHandler::OnCloseDialog(
354 const base::ListValue* args) {
355 DVLOG(1) << "OnCloseDialog";
356 if (dialog_closing_)
357 return;
359 dialog_closing_ = true;
360 media_router_ui_->Close();
363 bool MediaRouterWebUIMessageHandler::ActOnIssueType(
364 const IssueAction::Type& action_type,
365 const base::DictionaryValue* args) {
366 if (action_type == IssueAction::TYPE_LEARN_MORE) {
367 std::string learn_more_url = GetLearnMoreUrl(args);
368 if (learn_more_url.empty())
369 return false;
370 scoped_ptr<base::ListValue> open_args(new base::ListValue);
371 open_args->AppendString(learn_more_url);
372 web_ui()->CallJavascriptFunction(kWindowOpen, *open_args);
373 return true;
374 } else {
375 // Do nothing; no other issue action types require any other action.
376 return true;
380 } // namespace media_router