1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
#include <memory>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
#include "chrome/browser/ui/views/controls/hover_button.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_access_code_cast_button.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_metrics.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/menus/simple_menu_model.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/md_text_button_with_down_arrow.h"
#include "ui/views/controls/menu/menu_runner.h"
class Profile;
namespace media_router {
class CastDialogSinkView;
enum class MediaRouterDialogActivationLocation;
struct UIMediaSink;
// View component of the Cast dialog that allows users to start and stop Casting
// to devices. The list of devices used to populate the dialog is supplied by
// CastDialogModel.
class CastDialogView : public views::BubbleDialogDelegateView,
public CastDialogController::Observer,
public ui::SimpleMenuModel::Delegate {
METADATA_HEADER(CastDialogView, views::BubbleDialogDelegateView)
public:
class Observer : public base::CheckedObserver {
public:
virtual void OnDialogModelUpdated(CastDialogView* dialog_view) = 0;
virtual void OnDialogWillClose(CastDialogView* dialog_view) = 0;
};
enum SourceType { kTab, kDesktop };
CastDialogView(views::View* anchor_view,
views::BubbleBorder::Arrow anchor_position,
CastDialogController* controller,
Profile* profile,
const base::Time& start_time,
MediaRouterDialogActivationLocation activation_location,
actions::ActionItem* action_item = nullptr);
~CastDialogView() override;
CastDialogView(const CastDialogView&) = delete;
CastDialogView& operator=(const CastDialogView&) = delete;
// views::WidgetDelegate:
std::u16string GetWindowTitle() const override;
// CastDialogController::Observer:
void OnModelUpdated(const CastDialogModel& model) override;
void OnControllerDestroying() override;
// ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
void ExecuteCommand(int command_id, int event_flags) override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// If the dialog loses focus during a test and closes, the test can
// fail unexpectedly. This method prevents that by keeping the dialog from
// closing on blur.
void KeepShownForTesting();
// Called by tests.
const std::vector<raw_ptr<CastDialogSinkView, DanglingUntriaged>>&
sink_views_for_test() const {
return sink_views_;
}
views::ScrollView* scroll_view_for_test() { return scroll_view_; }
views::View* no_sinks_view_for_test() { return no_sinks_view_; }
views::View* permission_rejected_view_for_test() {
return permission_rejected_view_;
}
views::Button* sources_button_for_test() { return sources_button_; }
HoverButton* access_code_cast_button_for_test() {
return access_code_cast_button_;
}
ui::SimpleMenuModel* sources_menu_model_for_test() {
return sources_menu_model_.get();
}
views::MenuRunner* sources_menu_runner_for_test() {
return sources_menu_runner_.get();
}
private:
// TODO(crbug.com/1346127): Remove friend classes.
friend class CastDialogViewTest;
friend class MediaRouterCastUiForTest;
FRIEND_TEST_ALL_PREFIXES(CastDialogViewTest, DisableUnsupportedSinks);
FRIEND_TEST_ALL_PREFIXES(CastDialogViewTest, ShowAndHideDialog);
FRIEND_TEST_ALL_PREFIXES(CastDialogViewTest, ShowSourcesMenu);
// views::BubbleDialogDelegateView:
void Init() override;
void WindowClosing() override;
void ShowAccessCodeCastDialog();
void MaybeShowAccessCodeCastButton();
void ShowNoSinksView();
void ShowPermissionRejectedView();
void ShowScrollView();
void ResetViews();
// Applies the stored scroll state.
void RestoreSinkListState();
// Populates the scroll view containing sinks using the data in |model|.
void PopulateScrollView(const std::vector<UIMediaSink>& sinks);
void InitializeSourcesButton();
// Shows the sources menu that allows the user to choose a source to cast.
void ShowSourcesMenu();
// Stores |source| as the source to be used when user selects a sink to start
// casting, and updates the UI to reflect the selection.
void SelectSource(SourceType source);
void SinkPressed(size_t index);
void IssuePressed(size_t index);
void StopPressed(size_t index);
void FreezePressed(size_t index);
void MaybeSizeToContents();
// Returns the cast mode that is selected in the sources menu and supported by
// |sink|. Returns nullopt if no such cast mode exists.
std::optional<MediaCastMode> GetCastModeToUse(const UIMediaSink& sink) const;
// Disables sink buttons for sinks that do not support the currently selected
// source.
void DisableUnsupportedSinks();
// Posts a delayed task to record the number of sinks shown with the metrics
// recorder.
void RecordSinkCountWithDelay();
// Records the number of sinks shown with the metrics recorder.
void RecordSinkCount();
// Returns true iff feature is turned on and the access code casting policy
// has been enabled for this user.
bool IsAccessCodeCastingEnabled() const;
// Title shown at the top of the dialog.
std::u16string dialog_title_;
// The source selected in the sources menu. This defaults to "tab"
// (presentation or tab mirroring). "Tab" is represented by a single item in
// the sources menu.
SourceType selected_source_ = SourceType::kTab;
// Contains references to sink views in the order they appear.
std::vector<raw_ptr<CastDialogSinkView, DanglingUntriaged>> sink_views_;
raw_ptr<CastDialogController> controller_;
// ScrollView containing the list of sink buttons.
raw_ptr<views::ScrollView> scroll_view_ = nullptr;
// View shown while there are no sinks.
raw_ptr<views::View> no_sinks_view_ = nullptr;
raw_ptr<views::View> permission_rejected_view_ = nullptr;
const raw_ptr<Profile> profile_;
// How much |scroll_view_| is scrolled downwards in pixels. Whenever the sink
// list is updated the scroll position gets reset, so we must manually restore
// it to this value.
int scroll_position_ = 0;
// The access code cast button allows the user to add a cast device through
// the chrome://access-code-cast dialog.
raw_ptr<CastDialogAccessCodeCastButton> access_code_cast_button_ = nullptr;
// The sources menu allows the user to choose a source to cast.
raw_ptr<views::MdTextButtonWithDownArrow> sources_button_ = nullptr;
std::unique_ptr<ui::SimpleMenuModel> sources_menu_model_;
std::unique_ptr<views::MenuRunner> sources_menu_runner_;
// Records UMA metrics for the dialog's behavior.
CastDialogMetrics metrics_;
// The action item tied to this dialog and its anchor view.
// Used to handle bubble re-opening issues with Pinned Toolbar Buttons.
const raw_ptr<actions::ActionItem> action_item_ = nullptr;
// The sink that the user has selected to cast to. If the user is using
// multiple sinks at the same time, the last activated sink is used.
std::optional<size_t> selected_sink_index_;
base::ObserverList<Observer> observers_;
// When this is set to true, the dialog does not close on blur.
bool keep_shown_for_testing_ = false;
base::WeakPtrFactory<CastDialogView> weak_factory_{this};
};
} // namespace media_router
#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_VIEW_H_
|