Commit a9e209f6 authored by Tommy Steimel's avatar Tommy Steimel Committed by Commit Bot

GMC: Go back to tab when notification is clicked

This CL makes GMC notifications clickable. When clicked, the tab that
originated the media is focused.

Bug: 1011052
Change-Id: I4f14cf8f5d19e12afbb5eaf11c1b8e7ac1a042c8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1862868
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Reviewed-by: default avatarJazz Xu <jazzhsu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706728}
parent d3a4647f
<?xml version="1.0" encoding="utf-8"?>
<!-- Global Media Controls-specific strings (included from generated_resources.grd). -->
<grit-part>
<message name="IDS_GLOBAL_MEDIA_CONTROLS_BACK_TO_TAB" desc="A11y text for the Global Media Controls container describing how clicking it takes you back to the tab.">
Back to tab
</message>
<message name="IDS_GLOBAL_MEDIA_CONTROLS_ICON_TOOLTIP_TEXT" desc="Tooltip for the Global Media Controls icon, which appears in the toolbar. The tooltip appears on mouseover of the icon.">
Control your music, videos, and more
</message>
......
c19525fb78d22d1e8351eac5871b1ff939f32c36
\ No newline at end of file
......@@ -15,6 +15,9 @@ class MediaNotificationContainerObserver : public base::CheckedObserver {
// Called when the metadata displayed in the container changes.
virtual void OnContainerMetadataChanged() = 0;
// Called when the container is clicked.
virtual void OnContainerClicked(const std::string& id) = 0;
// Called when the container is dismissed from the dialog.
virtual void OnContainerDismissed(const std::string& id) = 0;
......
......@@ -213,6 +213,22 @@ void MediaToolbarButtonController::LogMediaSessionActionButtonPressed(
IsWebContentsFocused(web_contents));
}
void MediaToolbarButtonController::OnContainerClicked(const std::string& id) {
auto it = sessions_.find(id);
if (it == sessions_.end())
return;
content::WebContents* web_contents = it->second.web_contents();
if (!web_contents)
return;
content::WebContentsDelegate* delegate = web_contents->GetDelegate();
if (!delegate)
return;
delegate->ActivateContents(web_contents);
}
void MediaToolbarButtonController::OnContainerDismissed(const std::string& id) {
auto it = sessions_.find(id);
if (it != sessions_.end())
......
......@@ -64,6 +64,7 @@ class MediaToolbarButtonController
// MediaNotificationContainerObserver implementation.
void OnContainerExpanded(bool expanded) override {}
void OnContainerMetadataChanged() override {}
void OnContainerClicked(const std::string& id) override;
void OnContainerDismissed(const std::string& id) override;
void OnContainerDestroyed(const std::string& id) override;
......
......@@ -50,6 +50,7 @@ class MediaDialogView : public views::BubbleDialogDelegateView,
// MediaNotificationContainerObserver implementation.
void OnContainerExpanded(bool expanded) override;
void OnContainerMetadataChanged() override;
void OnContainerClicked(const std::string& id) override {}
void OnContainerDismissed(const std::string& id) override {}
void OnContainerDestroyed(const std::string& id) override;
......
......@@ -201,19 +201,19 @@ class MediaDialogViewBrowserTest : public InProcessBrowserTest {
void StartPlayback() {
// The test HTML files used in these tests contain "play()" functions that
// play the video.
GetWebContents()->GetMainFrame()->ExecuteJavaScriptForTests(
GetActiveWebContents()->GetMainFrame()->ExecuteJavaScriptForTests(
base::ASCIIToUTF16("play()"), base::NullCallback());
}
void WaitForStart() {
content::MediaStartStopObserver observer(
GetWebContents(), content::MediaStartStopObserver::Type::kStart);
GetActiveWebContents(), content::MediaStartStopObserver::Type::kStart);
observer.Wait();
}
void WaitForStop() {
content::MediaStartStopObserver observer(
GetWebContents(), content::MediaStartStopObserver::Type::kStop);
GetActiveWebContents(), content::MediaStartStopObserver::Type::kStop);
observer.Wait();
}
......@@ -240,6 +240,18 @@ class MediaDialogViewBrowserTest : public InProcessBrowserTest {
ClickButton(GetButtonForAction(MediaSessionAction::kPlay));
}
void ClickNotificationByTitle(const base::string16& title) {
ASSERT_TRUE(MediaDialogView::IsShowing());
MediaNotificationContainerImplView* notification =
GetNotificationByTitle(title);
ASSERT_NE(nullptr, notification);
ClickButton(notification);
}
content::WebContents* GetActiveWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
private:
void ClickButton(views::Button* button) {
base::RunLoop closure_loop;
......@@ -275,8 +287,18 @@ class MediaDialogViewBrowserTest : public InProcessBrowserTest {
return nullptr;
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
// Finds a MediaNotificationContainerImplView by title.
MediaNotificationContainerImplView* GetNotificationByTitle(
const base::string16& title) {
for (const auto notification_pair :
MediaDialogView::GetDialogViewForTesting()
->GetNotificationsForTesting()) {
const media_message_center::MediaNotificationView* view =
notification_pair.second->view_for_testing();
if (view->title_label_for_testing()->GetText() == title)
return notification_pair.second;
}
return nullptr;
}
base::test::ScopedFeatureList feature_list_;
......@@ -350,3 +372,39 @@ IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest, ShowsMultipleMediaSessions) {
WaitForDialogToContainText(base::ASCIIToUTF16("Different Title"));
WaitForDialogToContainText(base::ASCIIToUTF16("Another Artist"));
}
IN_PROC_BROWSER_TEST_F(MediaDialogViewBrowserTest,
ClickingOnNotificationGoesBackToTab) {
// Open a tab and play media.
OpenTestURL();
StartPlayback();
WaitForStart();
// Pointer to the first tab.
content::WebContents* first_web_contents = GetActiveWebContents();
// Open another tab and play different media.
OpenDifferentMetadataURLInNewTab();
StartPlayback();
WaitForStart();
// Now the active web contents is the second tab.
content::WebContents* second_web_contents = GetActiveWebContents();
ASSERT_NE(first_web_contents, second_web_contents);
// Open the media dialog.
ClickToolbarIcon();
WaitForDialogOpened();
EXPECT_TRUE(IsDialogVisible());
// Wait for the dialog to be populated.
WaitForDialogToContainText(base::ASCIIToUTF16("Big Buck Bunny"));
WaitForDialogToContainText(base::ASCIIToUTF16("Different Title"));
// The second tab should be the active tab.
EXPECT_EQ(second_web_contents, GetActiveWebContents());
// Clicking the first notification should make the first tab active.
ClickNotificationByTitle(base::ASCIIToUTF16("Big Buck Bunny"));
EXPECT_EQ(first_web_contents, GetActiveWebContents());
}
......@@ -57,12 +57,16 @@ class MediaNotificationContainerImplView::DismissButton
MediaNotificationContainerImplView::MediaNotificationContainerImplView(
const std::string& id,
base::WeakPtr<media_message_center::MediaNotificationItem> item)
: id_(id),
: views::Button(this),
id_(id),
foreground_color_(kDefaultForegroundColor),
background_color_(kDefaultBackgroundColor) {
SetLayoutManager(std::make_unique<views::FillLayout>());
SetPreferredSize(kNormalSize);
set_notify_enter_exit_on_child(true);
SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
SetTooltipText(
l10n_util::GetStringUTF16(IDS_GLOBAL_MEDIA_CONTROLS_BACK_TO_TAB));
swipeable_container_ = std::make_unique<views::View>();
swipeable_container_->set_owned_by_client();
......@@ -179,8 +183,14 @@ void MediaNotificationContainerImplView::OnSlideOut() {
void MediaNotificationContainerImplView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
DCHECK_EQ(dismiss_button_, sender);
DismissNotification();
if (sender == dismiss_button_) {
DismissNotification();
} else if (sender == this) {
for (auto& observer : observers_)
observer.OnContainerClicked(id_);
} else {
NOTREACHED();
}
}
void MediaNotificationContainerImplView::AddObserver(
......
......@@ -15,7 +15,6 @@
#include "ui/views/animation/slide_out_controller_delegate.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"
namespace media_message_center {
class MediaNotificationItem;
......@@ -31,7 +30,7 @@ class MediaNotificationContainerObserver;
// within the MediaDialogView. The media notification shows metadata for a media
// session and can control playback.
class MediaNotificationContainerImplView
: public views::View,
: public views::Button,
public media_message_center::MediaNotificationContainer,
public MediaNotificationContainerImpl,
public views::SlideOutControllerDelegate,
......@@ -43,7 +42,7 @@ class MediaNotificationContainerImplView
base::WeakPtr<media_message_center::MediaNotificationItem> item);
~MediaNotificationContainerImplView() override;
// views::View:
// views::Button:
void AddedToWidget() override;
void RemovedFromWidget() override;
void OnMouseEntered(const ui::MouseEvent& event) override;
......
......@@ -35,6 +35,7 @@ class MockMediaNotificationContainerObserver
// MediaNotificationContainerObserver implementation.
MOCK_METHOD1(OnContainerExpanded, void(bool expanded));
MOCK_METHOD0(OnContainerMetadataChanged, void());
MOCK_METHOD1(OnContainerClicked, void(const std::string& id));
MOCK_METHOD1(OnContainerDismissed, void(const std::string& id));
MOCK_METHOD1(OnContainerDestroyed, void(const std::string& id));
......@@ -124,6 +125,12 @@ class MediaNotificationContainerImplViewTest : public views::ViewsTestBase {
notification_container_->OnMouseExited(event);
}
void SimulateContainerClicked() {
ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
views::test::ButtonTestApi(notification_container_).NotifyClick(event);
}
void SimulateDismissButtonClicked() {
ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
......@@ -346,3 +353,8 @@ TEST_F(MediaNotificationContainerImplViewTest, SendsDestroyedUpdates) {
container.reset();
testing::Mock::VerifyAndClearExpectations(&observer);
}
TEST_F(MediaNotificationContainerImplViewTest, SendsClicks) {
EXPECT_CALL(observer(), OnContainerClicked(kTestNotificationId));
SimulateContainerClicked();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment