summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/ui/webui/media_router/media_router_ui.cc150
-rw-r--r--chrome/browser/ui/webui/media_router/media_router_ui.h90
-rw-r--r--chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc186
-rw-r--r--chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h19
4 files changed, 431 insertions, 14 deletions
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 893dc73..11078b4 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -6,34 +6,93 @@
#include <string>
+#include "chrome/browser/media/router/issues_observer.h"
+#include "chrome/browser/media/router/media_router.h"
+#include "chrome/browser/media/router/media_router_mojo_impl.h"
+#include "chrome/browser/media/router/media_router_mojo_impl_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.h"
#include "chrome/browser/ui/webui/media_router/media_router_resources_provider.h"
#include "chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h"
#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
namespace media_router {
+// This class calls to refresh the UI when the highest priority issue is
+// updated.
+class MediaRouterUI::UIIssuesObserver : public IssuesObserver {
+ public:
+ explicit UIIssuesObserver(MediaRouterUI* ui) : ui_(ui) { DCHECK(ui); }
+
+ ~UIIssuesObserver() override {}
+
+ // IssuesObserver implementation.
+ void OnIssueUpdated(const Issue* issue) override { ui_->SetIssue(issue); }
+
+ private:
+ // Reference back to the owning MediaRouterUI instance.
+ MediaRouterUI* ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(UIIssuesObserver);
+};
+
+class MediaRouterUI::UIMediaRoutesObserver : public MediaRoutesObserver {
+ public:
+ UIMediaRoutesObserver(MediaRouter* router, MediaRouterUI* ui)
+ : MediaRoutesObserver(router), ui_(ui) {
+ DCHECK(ui_);
+ }
+
+ void OnRoutesUpdated(const std::vector<MediaRoute>& routes) override {
+ ui_->OnRoutesUpdated(routes);
+ }
+
+ private:
+ // Reference back to the owning MediaRouterUI instance.
+ MediaRouterUI* ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(UIMediaRoutesObserver);
+};
+
MediaRouterUI::MediaRouterUI(content::WebUI* web_ui)
: ConstrainedWebDialogUI(web_ui),
- handler_(new MediaRouterWebUIMessageHandler()) {
+ handler_(new MediaRouterWebUIMessageHandler()),
+ ui_initialized_(false),
+ has_pending_route_request_(false),
+ router_(nullptr),
+ weak_factory_(this) {
// Create a WebUIDataSource containing the chrome://media-router page's
// content.
scoped_ptr<content::WebUIDataSource> html_source(
content::WebUIDataSource::Create(chrome::kChromeUIMediaRouterHost));
AddLocalizedStrings(html_source.get());
AddMediaRouterUIResources(html_source.get());
- Profile* profile = Profile::FromWebUI(web_ui);
// Ownership of |html_source| is transferred to the BrowserContext.
- content::WebUIDataSource::Add(profile, html_source.release());
+ content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
+ html_source.release());
+
// Ownership of |handler_| is transferred to |web_ui|.
web_ui->AddMessageHandler(handler_);
+
+ content::WebContents* wc = web_ui->GetWebContents();
+ DCHECK(wc);
+
+ router_ = MediaRouterMojoImplFactory::GetApiForBrowserContext(
+ wc->GetBrowserContext());
+ DCHECK(router_);
+
+ // Register for Issue and MediaRoute updates.
+ issues_observer_.reset(new UIIssuesObserver(this));
+ routes_observer_.reset(new UIMediaRoutesObserver(router_, this));
}
MediaRouterUI::~MediaRouterUI() {
+ if (query_result_manager_.get())
+ query_result_manager_->RemoveObserver(this);
}
void MediaRouterUI::Close() {
@@ -44,5 +103,90 @@ void MediaRouterUI::Close() {
}
}
+void MediaRouterUI::UIInitialized() {
+ ui_initialized_ = true;
+}
+
+bool MediaRouterUI::CreateRoute(const MediaSinkId& sink_id) {
+ return DoCreateRoute(sink_id, GetPreferredCastMode(cast_modes_));
+}
+
+bool MediaRouterUI::CreateRouteWithCastModeOverride(
+ const MediaSinkId& sink_id,
+ MediaCastMode cast_mode_override) {
+ // NOTE: It's actually not an override if
+ // |cast_mode_override| == |GetPreferredCastMode(cast_modes_)|.
+ return DoCreateRoute(sink_id, cast_mode_override);
+}
+
+void MediaRouterUI::CloseRoute(const MediaRouteId& route_id) {
+ router_->CloseRoute(route_id);
+}
+
+void MediaRouterUI::ClearIssue(const std::string& issue_id) {
+ router_->ClearIssue(issue_id);
+}
+
+std::string MediaRouterUI::GetInitialHeaderText() const {
+ if (cast_modes_.empty())
+ return std::string();
+
+ // TODO(imcheng): Pass in source_host_ once DEFAULT mode is upstreamed.
+ return MediaCastModeToTitle(GetPreferredCastMode(cast_modes_), std::string());
+}
+
+void MediaRouterUI::OnResultsUpdated(
+ const std::vector<MediaSinkWithCastModes>& sinks) {
+ sinks_ = sinks;
+ if (ui_initialized_)
+ handler_->UpdateSinks(sinks_);
+}
+
+void MediaRouterUI::SetIssue(const Issue* issue) {
+ if (ui_initialized_)
+ handler_->UpdateIssue(issue);
+}
+
+void MediaRouterUI::OnRoutesUpdated(const std::vector<MediaRoute>& routes) {
+ routes_ = routes;
+ if (ui_initialized_)
+ handler_->UpdateRoutes(routes_);
+}
+
+void MediaRouterUI::OnRouteResponseReceived(scoped_ptr<MediaRoute> route,
+ const std::string& error) {
+ DVLOG(1) << "OnRouteResponseReceived";
+ // TODO(imcheng): Display error in UI. (crbug.com/490372)
+ if (!route)
+ LOG(ERROR) << "MediaRouteResponse returned error: " << error;
+ else
+ handler_->AddRoute(*route);
+
+ has_pending_route_request_ = false;
+}
+
+bool MediaRouterUI::DoCreateRoute(const MediaSinkId& sink_id,
+ MediaCastMode cast_mode) {
+ DCHECK(query_result_manager_.get());
+
+ // Note that there is a rarely-encountered bug, where the MediaCastMode to
+ // MediaSource mapping could have been updated, between when the user
+ // clicked on the UI to start a create route request,
+ // and when this function is called.
+ // However, since the user does not have visibility into the MediaSource, and
+ // that it occurs very rarely in practice, we leave it as-is for now.
+ MediaSource source = query_result_manager_->GetSourceForCastMode(cast_mode);
+ if (source.Empty()) {
+ LOG(ERROR) << "No corresponding MediaSource for cast mode " << cast_mode;
+ return false;
+ }
+
+ has_pending_route_request_ = true;
+ router_->CreateRoute(source.id(), sink_id,
+ base::Bind(&MediaRouterUI::OnRouteResponseReceived,
+ weak_factory_.GetWeakPtr()));
+ return true;
+}
+
} // namespace media_router
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 6fcb304..1eb1db1 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -6,15 +6,24 @@
#define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/media/router/issue.h"
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
+#include "chrome/browser/ui/webui/media_router/media_cast_mode.h"
+#include "chrome/browser/ui/webui/media_router/media_sink_with_cast_modes.h"
+#include "chrome/browser/ui/webui/media_router/query_result_manager.h"
#include "content/public/browser/web_ui_data_source.h"
namespace media_router {
+class IssuesObserver;
class MediaRouterWebUIMessageHandler;
+class MediaRoutesObserver;
// Implements the chrome://media-router user interface.
-class MediaRouterUI : public ConstrainedWebDialogUI {
+class MediaRouterUI : public ConstrainedWebDialogUI,
+ public QueryResultManager::Observer {
public:
// |web_ui| owns this object and is used to initialize the base class.
explicit MediaRouterUI(content::WebUI* web_ui);
@@ -23,11 +32,90 @@ class MediaRouterUI : public ConstrainedWebDialogUI {
// Closes the media router UI.
void Close();
+ // Notifies this instance that the UI has been initialized.
+ void UIInitialized();
+
+ // Requests a route be created from the source determined by the preferred
+ // MediaCastMode, to the sink given by |sink_id|.
+ // The preferred cast mode is determined from the set of currently supported
+ // cast modes in |cast_modes_|.
+ // Returns false if unable to request the route.
+ // |OnRouteResponseReceived()| will be invoked when the route request
+ // completes.
+ bool CreateRoute(const MediaSinkId& sink_id);
+
+ // Requests a route be created from the source mapped to
+ // |cast_mode_override|, to the sink given by |sink_id|.
+ // Returns true if a route request is successfully submitted.
+ bool CreateRouteWithCastModeOverride(const MediaSinkId& sink_id,
+ MediaCastMode cast_mode_override);
+
+ // Calls MediaRouter to close the given route.
+ void CloseRoute(const MediaRouteId& route_id);
+
+ // Calls MediaRouter to clear the given issue.
+ void ClearIssue(const Issue::IssueId& issue_id);
+
+ // Returns the header text that should be displayed in the UI when it is
+ // initially loaded. The header text is determined by the preferred cast mode.
+ std::string GetInitialHeaderText() const;
+
+ bool has_pending_route_request() const { return has_pending_route_request_; }
+ const std::vector<MediaSinkWithCastModes>& sinks() const { return sinks_; }
+ const std::vector<MediaRoute>& routes() const { return routes_; }
+ const std::set<MediaCastMode>& cast_modes() const { return cast_modes_; }
+
private:
+ class UIIssuesObserver;
+ class UIMediaRoutesObserver;
+
+ // QueryResultManager::Observer
+ void OnResultsUpdated(
+ const std::vector<MediaSinkWithCastModes>& sinks) override;
+
+ // Called by |issues_observer_| when the top issue has changed.
+ // If the UI is already initialized, notifies |handler_| to update the UI.
+ // Ignored if the UI is not yet initialized.
+ void SetIssue(const Issue* issue);
+
+ // Called by |routes_observer_| when the set of active routes has changed.
+ void OnRoutesUpdated(const std::vector<MediaRoute>& routes);
+
+ // Callback passed to MediaRouter to receive response to route creation
+ // requests.
+ void OnRouteResponseReceived(scoped_ptr<MediaRoute> route,
+ const std::string& error);
+
+ bool DoCreateRoute(const MediaSinkId& sink_id, MediaCastMode cast_mode);
+
// Owned by the |web_ui| passed in the ctor, and guaranteed to be deleted
// only after it has deleted |this|.
MediaRouterWebUIMessageHandler* handler_;
+ // These are non-null while this instance is registered to receive
+ // updates from them.
+ scoped_ptr<IssuesObserver> issues_observer_;
+ scoped_ptr<MediaRoutesObserver> routes_observer_;
+
+ // Set to true by |handler_| when the UI has been initialized.
+ bool ui_initialized_;
+
+ // Set to |true| if there is a pending route request for this UI.
+ bool has_pending_route_request_;
+
+ std::vector<MediaSinkWithCastModes> sinks_;
+ std::vector<MediaRoute> routes_;
+ CastModeSet cast_modes_;
+
+ scoped_ptr<QueryResultManager> query_result_manager_;
+
+ // Cached pointer to the MediaRouter for this instance's BrowserContext.
+ MediaRouter* router_;
+
+ // NOTE: Weak pointers must be invalidated before all other member variables.
+ // Therefore |weak_factory_| must be placed at the end.
+ base::WeakPtrFactory<MediaRouterUI> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(MediaRouterUI);
};
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
index 183ae94..a752f74 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
@@ -6,7 +6,9 @@
#include "base/bind.h"
#include "chrome/browser/ui/webui/media_router/media_router_ui.h"
+#include "chrome/grit/generated_resources.h"
#include "content/public/browser/web_ui.h"
+#include "ui/base/l10n/l10n_util.h"
namespace media_router {
@@ -19,7 +21,74 @@ const char kActOnIssue[] = "actOnIssue";
const char kCloseRoute[] = "closeRoute";
const char kCloseDialog[] = "closeDialog";
-// TODO(imcheng): Define JS function names here.
+// JS function names.
+const char kSetInitialSettings[] = "media_router.setInitialSettings";
+const char kAddRoute[] = "media_router.ui.addRoute";
+const char kSetSinkList[] = "media_router.ui.setSinkList";
+const char kSetRouteList[] = "media_router.ui.setRouteList";
+const char kSetCastModeList[] = "media_router.ui.setCastModeList";
+
+scoped_ptr<base::ListValue> SinksToValue(
+ const std::vector<MediaSinkWithCastModes>& sinks) {
+ scoped_ptr<base::ListValue> value(new base::ListValue);
+
+ for (const MediaSinkWithCastModes& sink_with_cast_modes : sinks) {
+ scoped_ptr<base::DictionaryValue> sink_val(new base::DictionaryValue);
+
+ const MediaSink& sink = sink_with_cast_modes.sink;
+ sink_val->SetString("id", sink.id());
+ sink_val->SetString("name", sink.name());
+
+ scoped_ptr<base::ListValue> cast_modes_val(new base::ListValue);
+ for (MediaCastMode cast_mode : sink_with_cast_modes.cast_modes)
+ cast_modes_val->AppendInteger(cast_mode);
+ sink_val->Set("castModes", cast_modes_val.Pass());
+
+ value->Append(sink_val.release());
+ }
+
+ return value.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> RouteToValue(const MediaRoute& route) {
+ scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
+
+ dictionary->SetString("id", route.media_route_id());
+ dictionary->SetString("sinkId", route.media_sink().id());
+ dictionary->SetString("title", route.description());
+ dictionary->SetBoolean("isLocal", route.is_local());
+
+ return dictionary.Pass();
+}
+
+scoped_ptr<base::ListValue> RoutesToValue(
+ const std::vector<MediaRoute>& routes) {
+ scoped_ptr<base::ListValue> value(new base::ListValue);
+
+ for (const MediaRoute& route : routes) {
+ scoped_ptr<base::DictionaryValue> route_val(RouteToValue(route));
+ value->Append(route_val.release());
+ }
+
+ return value.Pass();
+}
+
+scoped_ptr<base::ListValue> CastModesToValue(const CastModeSet& cast_modes,
+ const std::string& source_host) {
+ scoped_ptr<base::ListValue> value(new base::ListValue);
+
+ for (const MediaCastMode& cast_mode : cast_modes) {
+ scoped_ptr<base::DictionaryValue> cast_mode_val(new base::DictionaryValue);
+ cast_mode_val->SetInteger("type", cast_mode);
+ cast_mode_val->SetString("title",
+ MediaCastModeToTitle(cast_mode, source_host));
+ cast_mode_val->SetString(
+ "description", MediaCastModeToDescription(cast_mode, source_host));
+ value->Append(cast_mode_val.release());
+ }
+
+ return value.Pass();
+}
} // namespace
@@ -30,6 +99,43 @@ MediaRouterWebUIMessageHandler::MediaRouterWebUIMessageHandler()
MediaRouterWebUIMessageHandler::~MediaRouterWebUIMessageHandler() {
}
+void MediaRouterWebUIMessageHandler::UpdateSinks(
+ const std::vector<MediaSinkWithCastModes>& sinks) {
+ DVLOG(2) << "UpdateSinks";
+ scoped_ptr<base::ListValue> sinks_val(SinksToValue(sinks));
+ web_ui()->CallJavascriptFunction(kSetSinkList, *sinks_val);
+}
+
+void MediaRouterWebUIMessageHandler::UpdateRoutes(
+ const std::vector<MediaRoute>& routes) {
+ DVLOG(2) << "UpdateRoutes";
+ scoped_ptr<base::ListValue> routes_val(RoutesToValue(routes));
+ web_ui()->CallJavascriptFunction(kSetRouteList, *routes_val);
+}
+
+void MediaRouterWebUIMessageHandler::UpdateCastModes(
+ const CastModeSet& cast_modes,
+ const std::string& source_host) {
+ DVLOG(2) << "UpdateCastModes";
+ scoped_ptr<base::ListValue> cast_modes_val(
+ CastModesToValue(cast_modes, source_host));
+ web_ui()->CallJavascriptFunction(kSetCastModeList, *cast_modes_val);
+}
+
+void MediaRouterWebUIMessageHandler::AddRoute(const MediaRoute& route) {
+ DVLOG(2) << "AddRoute";
+
+ scoped_ptr<base::DictionaryValue> route_value(RouteToValue(route));
+ web_ui()->CallJavascriptFunction(kAddRoute, *route_value);
+}
+
+void MediaRouterWebUIMessageHandler::UpdateIssue(const Issue* issue) {
+ DVLOG(2) << "UpdateIssue";
+ // TODO(imcheng): Implement conversion from Issue to dictionary object
+ // (crbug.com/464216).
+ NOTIMPLEMENTED();
+}
+
void MediaRouterWebUIMessageHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
kGetInitialSettings,
@@ -55,31 +161,93 @@ void MediaRouterWebUIMessageHandler::RegisterMessages() {
void MediaRouterWebUIMessageHandler::OnGetInitialSettings(
const base::ListValue* args) {
- // TODO(imcheng): Implement.
- NOTIMPLEMENTED();
+ MediaRouterUI* media_router_ui = GetMediaRouterUI();
+
+ base::DictionaryValue initial_settings;
+
+ initial_settings.SetString("headerText",
+ media_router_ui->GetInitialHeaderText());
+
+ scoped_ptr<base::ListValue> sinks(SinksToValue(media_router_ui->sinks()));
+ initial_settings.Set("sinks", sinks.release());
+
+ scoped_ptr<base::ListValue> routes(RoutesToValue(media_router_ui->routes()));
+ initial_settings.Set("routes", routes.release());
+
+ scoped_ptr<base::ListValue> cast_modes(CastModesToValue(
+ media_router_ui->cast_modes(),
+ // TODO(imcheng): Use media_router_ui->source_host() once DEFAULT mode
+ // is upstreamed.
+ std::string()));
+ initial_settings.Set("castModes", cast_modes.release());
+
+ web_ui()->CallJavascriptFunction(kSetInitialSettings, initial_settings);
+ media_router_ui->UIInitialized();
}
void MediaRouterWebUIMessageHandler::OnCreateRoute(
const base::ListValue* args) {
- // TODO(imcheng): Implement.
- NOTIMPLEMENTED();
+ std::string sink_id;
+ int cast_mode_num;
+ if (!args->GetString(0, &sink_id) || !args->GetInteger(1, &cast_mode_num)) {
+ LOG(ERROR) << "Unable to extract args.";
+ return;
+ }
+
+ if (sink_id.empty()) {
+ LOG(ERROR) << "Media Route Provider Manager did not respond with a "
+ << "valid sink ID. Aborting.";
+ return;
+ }
+
+ MediaRouterUI* media_router_ui =
+ static_cast<MediaRouterUI*>(web_ui()->GetController());
+ if (media_router_ui->has_pending_route_request()) {
+ LOG(ERROR) << "UI already has pending route request. Ignoring.";
+ return;
+ }
+
+ DVLOG(2) << "sink id: " << sink_id << ", cast mode: " << cast_mode_num;
+
+ // TODO(haibinlu): Pass additional parameters into the CreateRoute request,
+ // e.g. low-fps-mirror, user-override. (crbug.com/490364)
+ bool success = false;
+ if (IsValidCastModeNum(cast_mode_num)) {
+ // User explicitly selected cast mode.
+ DVLOG(2) << "Cast mode override: " << cast_mode_num;
+ success = media_router_ui->CreateRouteWithCastModeOverride(
+ sink_id, static_cast<MediaCastMode>(cast_mode_num));
+ } else {
+ success = media_router_ui->CreateRoute(sink_id);
+ }
+
+ // TODO(imcheng): Display error in UI. (crbug.com/490372)
+ if (!success)
+ LOG(ERROR) << "Error initiating route request.";
}
void MediaRouterWebUIMessageHandler::OnActOnIssue(
const base::ListValue* args) {
- // TODO(imcheng): Implement.
+ // TODO(imcheng): Implement (crbug.com/464216).
NOTIMPLEMENTED();
}
void MediaRouterWebUIMessageHandler::OnCloseRoute(
const base::ListValue* args) {
- // TODO(imcheng): Implement.
- NOTIMPLEMENTED();
+ DVLOG(2) << "OnCloseRoute";
+ std::string route_id;
+ if (!args->GetString(0, &route_id)) {
+ LOG(ERROR) << "Unable to extract args.";
+ return;
+ }
+ GetMediaRouterUI()->CloseRoute(route_id);
}
void MediaRouterWebUIMessageHandler::OnCloseDialog(
const base::ListValue* args) {
- CHECK(!dialog_closing_);
+ if (dialog_closing_)
+ return;
+
dialog_closing_ = true;
GetMediaRouterUI()->Close();
}
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h
index 2ad161f..742e87e 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h
@@ -5,7 +5,11 @@
#ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_WEBUI_MESSAGE_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_WEBUI_MESSAGE_HANDLER_H_
+#include <vector>
+
#include "base/macros.h"
+#include "chrome/browser/ui/webui/media_router/media_cast_mode.h"
+#include "chrome/browser/ui/webui/media_router/media_sink_with_cast_modes.h"
#include "content/public/browser/web_ui_message_handler.h"
namespace base {
@@ -14,6 +18,8 @@ class ListValue;
namespace media_router {
+class Issue;
+class MediaRoute;
class MediaRouterUI;
// The handler for Javascript messages related to the media router dialog.
@@ -22,10 +28,21 @@ class MediaRouterWebUIMessageHandler : public content::WebUIMessageHandler {
MediaRouterWebUIMessageHandler();
~MediaRouterWebUIMessageHandler() override;
+ // Methods to update the status displayed by the dialog.
+ void UpdateSinks(const std::vector<MediaSinkWithCastModes>& sinks);
+ void UpdateRoutes(const std::vector<MediaRoute>& routes);
+ void UpdateCastModes(const CastModeSet& cast_modes,
+ const std::string& source_host);
+ void AddRoute(const MediaRoute& route);
+
+ // Does not take ownership of |issue|. Note that |issue| can be nullptr, when
+ // there are no more issues.
+ void UpdateIssue(const Issue* issue);
+
+ private:
// WebUIMessageHandler implementation.
void RegisterMessages() override;
- private:
// Handlers for JavaScript messages.
void OnGetInitialSettings(const base::ListValue* args);
void OnCreateRoute(const base::ListValue* args);