| // Copyright 2015 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. |
| |
| #ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_ |
| #define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_ |
| |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/macros.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/media/router/issue.h" |
| #include "chrome/browser/media/router/media_source.h" |
| #include "chrome/browser/media/router/presentation_service_delegate_impl.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 content { |
| class WebContents; |
| } // namespace content |
| |
| namespace media_router { |
| |
| class IssuesObserver; |
| class MediaRoute; |
| class MediaRouter; |
| class MediaRouterDialogCallbacks; |
| class MediaRouterMojoImpl; |
| class MediaRouterWebUIMessageHandler; |
| class MediaRoutesObserver; |
| class MediaSink; |
| class MediaSinksObserver; |
| class CreatePresentationConnectionRequest; |
| |
| // Implements the chrome://media-router user interface. |
| class MediaRouterUI : public ConstrainedWebDialogUI, |
| public QueryResultManager::Observer, |
| public PresentationServiceDelegateImpl:: |
| DefaultPresentationRequestObserver { |
| public: |
| // |web_ui| owns this object and is used to initialize the base class. |
| explicit MediaRouterUI(content::WebUI* web_ui); |
| ~MediaRouterUI() override; |
| |
| // Initializes internal state (e.g. starts listening for MediaSinks) for |
| // targeting the default MediaSource (if any) of the initiator tab that owns |
| // |delegate|, as well as mirroring sources of that tab. |
| // The contents of the UI will change as the default MediaSource changes. |
| // If there is a default MediaSource, then DEFAULT MediaCastMode will be |
| // added to |cast_modes_|. |
| // Init* methods can only be called once. |
| // |delegate|: PresentationServiceDelegateImpl of the initiator tab. |
| // Must not be null. |
| // TODO(imcheng): Replace use of impl with an intermediate abstract |
| // interface. |
| void InitWithDefaultMediaSource( |
| const base::WeakPtr<PresentationServiceDelegateImpl>& delegate); |
| |
| // Initializes internal state targeting the presentation specified in |
| // |request|. Also sets up mirroring sources based on |initiator|. |
| // This is different from |InitWithDefaultMediaSource| in that it does not |
| // listen for default media source changes, as the UI is fixed to the source |
| // in |request|. |
| // Init* methods can only be called once. |
| // |initiator|: Reference to the WebContents that initiated the dialog. |
| // Must not be null. |
| // |delegate|: PresentationServiceDelegateImpl of the initiator tab. |
| // Must not be null. |
| // |presentation_request|: The presentation request. This instance will take |
| // ownership of it. Must not be null. |
| void InitWithPresentationSessionRequest( |
| content::WebContents* initiator, |
| const base::WeakPtr<PresentationServiceDelegateImpl>& delegate, |
| scoped_ptr<CreatePresentationConnectionRequest> presentation_request); |
| |
| // 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 mapped to |
| // |cast_mode|, to the sink given by |sink_id|. |
| // Returns true if a route request is successfully submitted. |
| // |OnRouteResponseReceived()| will be invoked when the route request |
| // completes. |
| bool CreateRoute(const MediaSink::Id& sink_id, MediaCastMode cast_mode); |
| |
| // Calls MediaRouter to close the given route. |
| void CloseRoute(const MediaRoute::Id& route_id); |
| |
| // Calls MediaRouter to add the given issue. |
| void AddIssue(const Issue& issue); |
| |
| // Calls MediaRouter to clear the given issue. |
| void ClearIssue(const Issue::Id& issue_id); |
| |
| // Returns the hostname of the default source's parent frame URL. |
| std::string GetFrameURLHost() const; |
| bool HasPendingRouteRequest() const { |
| return current_route_request_id_ != -1; |
| } |
| 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_; } |
| const content::WebContents* initiator() const { return initiator_; } |
| |
| // Marked virtual for tests. |
| virtual const std::string& GetRouteProviderExtensionId() const; |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, |
| UIMediaRoutesObserverFiltersNonDisplayRoutes); |
| |
| class UIIssuesObserver; |
| class UIMediaRoutesObserver : public MediaRoutesObserver { |
| public: |
| using RoutesUpdatedCallback = |
| base::Callback<void(const std::vector<MediaRoute>&)>; |
| UIMediaRoutesObserver(MediaRouter* router, |
| const RoutesUpdatedCallback& callback); |
| ~UIMediaRoutesObserver() override; |
| |
| // MediaRoutesObserver |
| void OnRoutesUpdated(const std::vector<MediaRoute>& routes) override; |
| |
| private: |
| // Callback to the owning MediaRouterUI instance. |
| RoutesUpdatedCallback callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(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(const int route_request_id, |
| const MediaSink::Id& sink_id, |
| const MediaRoute* route, |
| const std::string& presentation_id, |
| const std::string& error); |
| |
| // Creates and sends an issue if route creation times out. |
| void RouteCreationTimeout(); |
| |
| // Initializes the dialog with mirroring sources derived from |initiator|. |
| void InitCommon(content::WebContents* initiator); |
| |
| // PresentationServiceDelegateImpl::DefaultPresentationObserver |
| void OnDefaultPresentationChanged( |
| const PresentationRequest& presentation_request) override; |
| void OnDefaultPresentationRemoved() override; |
| |
| // Updates the set of supported cast modes and sends the updated set to |
| // |handler_|. |
| void UpdateCastModes(); |
| |
| // Returns the default presentation request's frame URL if there is one. |
| // Otherwise returns an empty GURL. |
| GURL GetFrameURL() const; |
| |
| // 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_; |
| |
| bool requesting_route_for_default_source_; |
| |
| // Set to -1 if not tracking a pending route request. |
| int current_route_request_id_; |
| |
| // Sequential counter for route requests. Used to update |
| // |current_route_request_id_| when there is a new route request. |
| int route_request_counter_; |
| |
| std::vector<MediaSinkWithCastModes> sinks_; |
| std::vector<MediaRoute> routes_; |
| CastModeSet cast_modes_; |
| |
| scoped_ptr<QueryResultManager> query_result_manager_; |
| |
| // If set, then the result of the next presentation route request will |
| // be handled by this object. |
| scoped_ptr<CreatePresentationConnectionRequest> create_session_request_; |
| |
| // Set to the presentation request corresponding to the presentation cast |
| // mode, if supported. Otherwise set to nullptr. |
| scoped_ptr<PresentationRequest> presentation_request_; |
| |
| // It's possible for PresentationServiceDelegateImpl to be destroyed before |
| // this class. |
| // (e.g. if a tab with the UI open is closed, then the tab WebContents will |
| // be destroyed first momentarily before the UI WebContents). |
| // Holding a WeakPtr to PresentationServiceDelegateImpl is the cleanest way to |
| // handle this. |
| // TODO(imcheng): hold a weak ptr to an abstract type instead. |
| base::WeakPtr<PresentationServiceDelegateImpl> presentation_service_delegate_; |
| |
| content::WebContents* initiator_; |
| |
| // Pointer to the MediaRouter for this instance's BrowserContext. |
| MediaRouterMojoImpl* router_; |
| |
| // Timer used to implement a timeout on a create route request. |
| base::OneShotTimer route_creation_timer_; |
| |
| // 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); |
| }; |
| |
| } // namespace media_router |
| |
| #endif // CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_ |