[MediaControls] Non-touch Prototype
Media controls' prototype for non-touch devices.
Bug: 928443
Change-Id: I49ba8007a3ee7e99245a698e1579ac1988a4f2d0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504213
Reviewed-by: Mounir Lamouri <mlamouri@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Commit-Queue: Jazz Xu <jazzhsu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#640525}
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 26ed9a0d..9cd46b7 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -293,6 +293,7 @@
"media_controls/media_controls_impl_test.cc",
"media_controls/media_controls_orientation_lock_delegate_test.cc",
"media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc",
+ "media_controls/non_touch/media_controls_non_touch_impl_test.cc",
"mediastream/media_constraints_test.cc",
"mediastream/media_devices_test.cc",
"notifications/notification_data_test.cc",
diff --git a/third_party/blink/renderer/modules/media_controls/BUILD.gn b/third_party/blink/renderer/modules/media_controls/BUILD.gn
index 680021e..f95ad65 100644
--- a/third_party/blink/renderer/modules/media_controls/BUILD.gn
+++ b/third_party/blink/renderer/modules/media_controls/BUILD.gn
@@ -88,6 +88,11 @@
"media_controls_resource_loader.h",
"media_controls_rotate_to_fullscreen_delegate.cc",
"media_controls_rotate_to_fullscreen_delegate.h",
+ "non_touch/media_controls_non_touch_impl.cc",
+ "non_touch/media_controls_non_touch_impl.h",
+ "non_touch/media_controls_non_touch_media_event_listener.cc",
+ "non_touch/media_controls_non_touch_media_event_listener.h",
+ "non_touch/media_controls_non_touch_media_event_listener_observer.h",
]
deps = [
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc
new file mode 100644
index 0000000..6d4782523
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.cc
@@ -0,0 +1,88 @@
+// Copyright 2019 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.
+
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h"
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h"
+#include "third_party/blink/renderer/platform/keyboard_codes.h"
+
+namespace blink {
+
+MediaControlsNonTouchImpl::MediaControlsNonTouchImpl(
+ HTMLMediaElement& media_element)
+ : HTMLDivElement(media_element.GetDocument()),
+ MediaControls(media_element),
+ media_event_listener_(
+ MakeGarbageCollected<MediaControlsNonTouchMediaEventListener>(
+ media_element)) {
+ SetShadowPseudoId(AtomicString("-internal-media-controls-non-touch"));
+ media_event_listener_->AddObserver(this);
+}
+
+MediaControlsNonTouchImpl* MediaControlsNonTouchImpl::Create(
+ HTMLMediaElement& media_element,
+ ShadowRoot& shadow_root) {
+ MediaControlsNonTouchImpl* controls =
+ MakeGarbageCollected<MediaControlsNonTouchImpl>(media_element);
+ shadow_root.ParserAppendChild(controls);
+ return controls;
+}
+
+Node::InsertionNotificationRequest MediaControlsNonTouchImpl::InsertedInto(
+ ContainerNode& root) {
+ media_event_listener_->Attach();
+ return HTMLDivElement::InsertedInto(root);
+}
+
+void MediaControlsNonTouchImpl::RemovedFrom(ContainerNode& insertion_point) {
+ HTMLDivElement::RemovedFrom(insertion_point);
+ Hide();
+ media_event_listener_->Detach();
+}
+
+void MediaControlsNonTouchImpl::MaybeShow() {
+ // show controls
+}
+
+void MediaControlsNonTouchImpl::Hide() {
+ // hide controls
+}
+
+void MediaControlsNonTouchImpl::OnFocusIn() {
+ if (MediaElement().ShouldShowControls())
+ MaybeShow();
+}
+
+void MediaControlsNonTouchImpl::OnKeyDown(KeyboardEvent* event) {
+ bool handled = true;
+ switch (event->keyCode()) {
+ case VKEY_RETURN:
+ MediaElement().TogglePlayState();
+ break;
+ case VKEY_LEFT:
+ case VKEY_RIGHT:
+ case VKEY_UP:
+ case VKEY_DOWN:
+ // do something
+ break;
+ default:
+ handled = false;
+ break;
+ }
+
+ if (handled)
+ event->SetDefaultHandled();
+}
+
+void MediaControlsNonTouchImpl::Trace(blink::Visitor* visitor) {
+ visitor->Trace(media_event_listener_);
+ MediaControls::Trace(visitor);
+ HTMLDivElement::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h
new file mode 100644
index 0000000..cb278933
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h
@@ -0,0 +1,72 @@
+// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_IMPL_H_
+
+#include "third_party/blink/renderer/core/html/html_div_element.h"
+#include "third_party/blink/renderer/core/html/media/media_controls.h"
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+
+namespace blink {
+
+class MediaControlsNonTouchMediaEventListener;
+
+class MODULES_EXPORT MediaControlsNonTouchImpl final
+ : public HTMLDivElement,
+ public MediaControls,
+ public MediaControlsNonTouchMediaEventListenerObserver {
+ USING_GARBAGE_COLLECTED_MIXIN(MediaControlsNonTouchImpl);
+
+ public:
+ static MediaControlsNonTouchImpl* Create(HTMLMediaElement&, ShadowRoot&);
+
+ explicit MediaControlsNonTouchImpl(HTMLMediaElement&);
+
+ // Node override.
+ Node::InsertionNotificationRequest InsertedInto(ContainerNode&) override;
+ void RemovedFrom(ContainerNode&) override;
+
+ // MediaControls implementation.
+ void MaybeShow() override;
+ void Hide() override;
+ void Reset() override {}
+ void OnControlsListUpdated() override {}
+ void OnTrackElementFailedToLoad() override {}
+ void NetworkStateChanged() override {}
+ LayoutObject* PanelLayoutObject() override { return nullptr; }
+ LayoutObject* TimelineLayoutObject() override { return nullptr; }
+ LayoutObject* ButtonPanelLayoutObject() override { return nullptr; }
+ LayoutObject* ContainerLayoutObject() override { return nullptr; }
+ void SetTestMode(bool) override {}
+ HTMLDivElement* PanelElement() override { return nullptr; }
+ void OnMediaControlsEnabledChange() override {}
+
+ // MediaControlsNonTouchMediaEventListenerObserver implementation.
+ void OnFocusIn() override;
+ void OnTimeUpdate() override {}
+ void OnDurationChange() override {}
+ void OnPlay() override {}
+ void OnPause() override {}
+ void OnError() override {}
+ void OnLoadedMetadata() override {}
+ void OnKeyPress(KeyboardEvent* event) override {}
+ void OnKeyDown(KeyboardEvent* event) override;
+ void OnKeyUp(KeyboardEvent* event) override {}
+
+ void Trace(blink::Visitor*) override;
+
+ private:
+ friend class MediaControlsNonTouchImplTest;
+
+ // Node
+ bool IsMediaControls() const override { return true; }
+
+ Member<MediaControlsNonTouchMediaEventListener> media_event_listener_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_IMPL_H_
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc
new file mode 100644
index 0000000..dbc8b42d
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl_test.cc
@@ -0,0 +1,82 @@
+// Copyright 2019 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.
+
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_impl.h"
+
+#include <memory>
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/core/html/media/html_media_test_helper.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/core/loader/empty_clients.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/keyboard_codes.h"
+#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
+
+namespace blink {
+
+namespace {
+
+class MockWebMediaPlayerForNonTouchImpl : public EmptyWebMediaPlayer {
+ public:
+ bool HasVideo() const override { return true; }
+};
+
+class MediaControlsNonTouchImplTest : public PageTestBase {
+ protected:
+ void SetUp() override { InitializePage(); }
+
+ void InitializePage() {
+ Page::PageClients clients;
+ FillWithEmptyClients(clients);
+ clients.chrome_client = MakeGarbageCollected<EmptyChromeClient>();
+ SetupPageWithClients(
+ &clients, test::MediaStubLocalFrameClient::Create(
+ std::make_unique<MockWebMediaPlayerForNonTouchImpl>()));
+
+ GetDocument().write("<video>");
+ HTMLMediaElement& video =
+ ToHTMLVideoElement(*GetDocument().QuerySelector("video"));
+ media_controls_ = MediaControlsNonTouchImpl::Create(
+ video, video.EnsureUserAgentShadowRoot());
+ }
+
+ MediaControlsNonTouchImpl& MediaControls() { return *media_controls_; }
+
+ void SimulateKeydownEvent(Element& element, int key_code) {
+ KeyboardEventInit* keyboard_event_init = KeyboardEventInit::Create();
+ keyboard_event_init->setKeyCode(key_code);
+
+ Event* keyboard_event =
+ MakeGarbageCollected<KeyboardEvent>("keydown", keyboard_event_init);
+ element.DispatchEvent(*keyboard_event);
+ }
+
+ private:
+ Persistent<MediaControlsNonTouchImpl> media_controls_;
+};
+
+TEST_F(MediaControlsNonTouchImplTest, PlayPause) {
+ MediaControls().MediaElement().SetFocused(true,
+ WebFocusType::kWebFocusTypeNone);
+ MediaControls().MediaElement().Play();
+ ASSERT_FALSE(MediaControls().MediaElement().paused());
+
+ // Press center key and video should be paused.
+ SimulateKeydownEvent(MediaControls().MediaElement(), VKEY_RETURN);
+ ASSERT_TRUE(MediaControls().MediaElement().paused());
+
+ // Press center key and video should be played.
+ SimulateKeydownEvent(MediaControls().MediaElement(), VKEY_RETURN);
+ ASSERT_FALSE(MediaControls().MediaElement().paused());
+}
+
+} // namespace
+
+} // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.cc b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.cc
new file mode 100644
index 0000000..2ee0746
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.cc
@@ -0,0 +1,116 @@
+// Copyright 2019 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.
+
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h"
+
+#include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/html/media/html_media_element.h"
+#include "third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h"
+
+namespace blink {
+
+MediaControlsNonTouchMediaEventListener::
+ MediaControlsNonTouchMediaEventListener(HTMLMediaElement& media_element)
+ : media_element_(media_element) {
+ if (media_element.isConnected())
+ Attach();
+}
+
+void MediaControlsNonTouchMediaEventListener::AddObserver(
+ MediaControlsNonTouchMediaEventListenerObserver* observer) {
+ observers_.insert(observer);
+}
+
+void MediaControlsNonTouchMediaEventListener::RemoveObserver(
+ MediaControlsNonTouchMediaEventListenerObserver* observer) {
+ observers_.erase(observer);
+}
+
+void MediaControlsNonTouchMediaEventListener::Attach() {
+ DCHECK(media_element_->isConnected());
+
+ media_element_->addEventListener(event_type_names::kFocusin, this, false);
+ media_element_->addEventListener(event_type_names::kTimeupdate, this, false);
+ media_element_->addEventListener(event_type_names::kDurationchange, this,
+ false);
+
+ media_element_->addEventListener(event_type_names::kPlay, this, false);
+ media_element_->addEventListener(event_type_names::kPause, this, false);
+
+ media_element_->addEventListener(event_type_names::kError, this, false);
+ media_element_->addEventListener(event_type_names::kLoadedmetadata, this,
+ false);
+
+ media_element_->addEventListener(event_type_names::kKeypress, this, false);
+ media_element_->addEventListener(event_type_names::kKeydown, this, false);
+ media_element_->addEventListener(event_type_names::kKeyup, this, false);
+}
+
+void MediaControlsNonTouchMediaEventListener::Detach() {
+ DCHECK(!media_element_->isConnected());
+}
+
+void MediaControlsNonTouchMediaEventListener::Invoke(
+ ExecutionContext* execution_context,
+ Event* event) {
+ if (event->type() == event_type_names::kFocusin) {
+ for (auto& observer : observers_)
+ observer->OnFocusIn();
+ return;
+ }
+ if (event->type() == event_type_names::kTimeupdate) {
+ for (auto& observer : observers_)
+ observer->OnTimeUpdate();
+ return;
+ }
+ if (event->type() == event_type_names::kDurationchange) {
+ for (auto& observer : observers_)
+ observer->OnDurationChange();
+ return;
+ }
+ if (event->type() == event_type_names::kPlay) {
+ for (auto& observer : observers_)
+ observer->OnPlay();
+ return;
+ }
+ if (event->type() == event_type_names::kPause) {
+ for (auto& observer : observers_)
+ observer->OnPause();
+ return;
+ }
+ if (event->type() == event_type_names::kError) {
+ for (auto& observer : observers_)
+ observer->OnError();
+ return;
+ }
+ if (event->type() == event_type_names::kLoadedmetadata) {
+ for (auto& observer : observers_)
+ observer->OnLoadedMetadata();
+ return;
+ }
+ if (event->type() == event_type_names::kKeypress) {
+ for (auto& observer : observers_)
+ observer->OnKeyPress(ToKeyboardEvent(event));
+ return;
+ }
+ if (event->type() == event_type_names::kKeydown) {
+ for (auto& observer : observers_)
+ observer->OnKeyDown(ToKeyboardEvent(event));
+ return;
+ }
+ if (event->type() == event_type_names::kKeyup) {
+ for (auto& observer : observers_)
+ observer->OnKeyUp(ToKeyboardEvent(event));
+ return;
+ }
+}
+
+void MediaControlsNonTouchMediaEventListener::Trace(blink::Visitor* visitor) {
+ NativeEventListener::Trace(visitor);
+ visitor->Trace(media_element_);
+ visitor->Trace(observers_);
+}
+
+} // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h
new file mode 100644
index 0000000..39329a67
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener.h
@@ -0,0 +1,41 @@
+// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_H_
+
+#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+
+namespace blink {
+
+class HTMLMediaElement;
+class MediaControlsNonTouchMediaEventListenerObserver;
+
+class MediaControlsNonTouchMediaEventListener final
+ : public NativeEventListener {
+ public:
+ explicit MediaControlsNonTouchMediaEventListener(HTMLMediaElement&);
+
+ void AddObserver(MediaControlsNonTouchMediaEventListenerObserver*);
+ void RemoveObserver(MediaControlsNonTouchMediaEventListenerObserver*);
+
+ void Attach();
+ void Detach();
+
+ void Trace(blink::Visitor*) override;
+ void Invoke(ExecutionContext*, Event*) override;
+
+ private:
+ HTMLMediaElement& GetMediaElement();
+
+ HeapListHashSet<Member<MediaControlsNonTouchMediaEventListenerObserver>>
+ observers_;
+ Member<HTMLMediaElement> media_element_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaControlsNonTouchMediaEventListener);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_H_
diff --git a/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h
new file mode 100644
index 0000000..3d7d55b
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_controls/non_touch/media_controls_non_touch_media_event_listener_observer.h
@@ -0,0 +1,29 @@
+// Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_OBSERVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_OBSERVER_H_
+
+namespace blink {
+
+class KeyboardEvent;
+
+class MediaControlsNonTouchMediaEventListenerObserver
+ : public GarbageCollectedMixin {
+ public:
+ virtual void OnFocusIn() = 0;
+ virtual void OnTimeUpdate() = 0;
+ virtual void OnDurationChange() = 0;
+ virtual void OnPlay() = 0;
+ virtual void OnPause() = 0;
+ virtual void OnError() = 0;
+ virtual void OnLoadedMetadata() = 0;
+ virtual void OnKeyPress(KeyboardEvent* event) = 0;
+ virtual void OnKeyDown(KeyboardEvent* event) = 0;
+ virtual void OnKeyUp(KeyboardEvent* event) = 0;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIA_CONTROLS_NON_TOUCH_MEDIA_CONTROLS_NON_TOUCH_MEDIA_EVENT_LISTENER_OBSERVER_H_