Use System Media Transport Controls to get media keys when available

This CL adds a new MediaKeysListener implementation for Windows that
connects to the System Media Transport Controls in order to get media
key events. This is much more user-friendly than using RegisterHotKey
especially when the user has other OS apps open that use media keys.

We will still fall back to the RegisterHotKey method whenever System
Media Transport Controls is unavailable.

Bug: 948920
Change-Id: I88c7895194783f22f880f8d493c406e12f6cb246
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1546204
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Reviewed-by: Robert Liao <robliao@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#648923}
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.cc b/chrome/browser/extensions/global_shortcut_listener_win.cc
index f5d0ac4..c5125495 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.cc
+++ b/chrome/browser/extensions/global_shortcut_listener_win.cc
@@ -72,25 +72,19 @@
     const ui::Accelerator& accelerator) {
   DCHECK(hotkeys_.find(accelerator) == hotkeys_.end());
 
-  // If we want to listen for media keys, we should do that through the
-  // MediaKeysListenerManager, which will tell the manager to send us media keys
-  // and prevent the HardwareKeyMediaController from receiving the keys.
+  // TODO(https://crbug.com/950704): We should be using
+  // |media_keys_listener_manager->StartWatchingMediaKey(...)| here, but that
+  // currently breaks the GlobalCommandsApiTest.GlobalDuplicatedMediaKey test.
+  // Instead, we'll just disable the MediaKeysListenerManager handling here, and
+  // listen using the fallback RegisterHotKey method.
   if (content::MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled() &&
       Command::IsMediaKey(accelerator)) {
     content::MediaKeysListenerManager* media_keys_listener_manager =
         content::MediaKeysListenerManager::GetInstance();
     DCHECK(media_keys_listener_manager);
 
-    bool success = media_keys_listener_manager->StartWatchingMediaKey(
-        accelerator.key_code(), this);
-
-    // Map the hot key to nullptr, since we don't need a
-    // SingletonHwndHotKeyObserver when the MediaKeysListenerManager is taking
-    // care of it.
-    if (success)
-      hotkeys_[accelerator] = nullptr;
-
-    return success;
+    registered_media_keys_++;
+    media_keys_listener_manager->DisableInternalMediaKeyHandling();
   }
 
   // Convert Accelerator modifiers to OS modifiers.
@@ -120,16 +114,19 @@
   HotKeyMap::iterator it = hotkeys_.find(accelerator);
   DCHECK(it != hotkeys_.end());
 
-  // If we're routing media keys through the MediaKeysListenerManager, then
-  // inform the manager that we're no longer listening to the given key.
+  // TODO(https://crbug.com/950704): We should be using
+  // |media_keys_listener_manager->StopWatchingMediaKey(...)| here.
   if (content::MediaKeysListenerManager::IsMediaKeysListenerManagerEnabled() &&
       Command::IsMediaKey(accelerator)) {
-    content::MediaKeysListenerManager* media_keys_listener_manager =
-        content::MediaKeysListenerManager::GetInstance();
-    DCHECK(media_keys_listener_manager);
+    registered_media_keys_--;
+    DCHECK_GE(registered_media_keys_, 0);
+    if (registered_media_keys_ == 0) {
+      content::MediaKeysListenerManager* media_keys_listener_manager =
+          content::MediaKeysListenerManager::GetInstance();
+      DCHECK(media_keys_listener_manager);
 
-    media_keys_listener_manager->StopWatchingMediaKey(accelerator.key_code(),
-                                                      this);
+      media_keys_listener_manager->EnableInternalMediaKeyHandling();
+    }
   }
 
   hotkeys_.erase(it);
diff --git a/chrome/browser/extensions/global_shortcut_listener_win.h b/chrome/browser/extensions/global_shortcut_listener_win.h
index 800c5c9..d7b245a 100644
--- a/chrome/browser/extensions/global_shortcut_listener_win.h
+++ b/chrome/browser/extensions/global_shortcut_listener_win.h
@@ -46,6 +46,9 @@
   // Whether this object is listening for global shortcuts.
   bool is_listening_;
 
+  // The number of media keys currently registered.
+  int registered_media_keys_ = 0;
+
   // A map of registered accelerators and their registration ids. The value is
   // null for media keys if kHardwareMediaKeyHandling is true.
   using HotKeyMap = std::map<ui::Accelerator,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index bc9134a..b6fa8404 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2097,10 +2097,15 @@
       # with the windows 8 sdk it does the wrong thing.
       "__ATLHOST_H__",
     ]
+    sources += [
+      "media/system_media_controls_notifier.cc",
+      "media/system_media_controls_notifier.h",
+    ]
     deps += [
       "//third_party/blink/public/common:font_unique_name_table_proto",
       "//third_party/iaccessible2",
       "//third_party/isimpledom",
+      "//ui/base/win/system_media_controls",
     ]
     libs += [
       "comctl32.lib",
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc
index 6e0472dc..9cfc9a2 100644
--- a/content/browser/media/media_keys_listener_manager_impl.cc
+++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -22,6 +22,10 @@
 #include "ui/base/now_playing/now_playing_info_center_delegate.h"
 #endif
 
+#if defined(OS_WIN)
+#include "content/browser/media/system_media_controls_notifier.h"
+#endif
+
 namespace content {
 
 MediaKeysListenerManagerImpl::ListeningData::ListeningData()
@@ -159,6 +163,12 @@
   }
 #endif
 
+#if defined(OS_WIN)
+  system_media_controls_notifier_ =
+      std::make_unique<SystemMediaControlsNotifier>(connector_);
+  system_media_controls_notifier_->Initialize();
+#endif  // defined(OS_WIN)
+
   auxiliary_services_started_ = true;
 }
 
diff --git a/content/browser/media/media_keys_listener_manager_impl.h b/content/browser/media/media_keys_listener_manager_impl.h
index be19904..f37dd5f5 100644
--- a/content/browser/media/media_keys_listener_manager_impl.h
+++ b/content/browser/media/media_keys_listener_manager_impl.h
@@ -28,6 +28,10 @@
 class NowPlayingInfoCenterNotifier;
 #endif
 
+#if defined(OS_WIN)
+class SystemMediaControlsNotifier;
+#endif  // defined(OS_WIN)
+
 // Listens for media keys and decides which listeners receive which events. In
 // particular, it owns one of its delegates (HardwareKeyMediaController), and
 // only propagates to the HardwareKeyMediaController if no other delegates are
@@ -114,6 +118,10 @@
       now_playing_info_center_notifier_;
 #endif
 
+#if defined(OS_WIN)
+  std::unique_ptr<SystemMediaControlsNotifier> system_media_controls_notifier_;
+#endif  // defined(OS_WIN)
+
   DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerManagerImpl);
 };
 
diff --git a/content/browser/media/system_media_controls_notifier.cc b/content/browser/media/system_media_controls_notifier.cc
new file mode 100644
index 0000000..2d701e2
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier.cc
@@ -0,0 +1,75 @@
+// 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 "content/browser/media/system_media_controls_notifier.h"
+
+#include <memory>
+#include <utility>
+
+#include "services/media_session/public/mojom/constants.mojom.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace content {
+
+using ABI::Windows::Media::MediaPlaybackStatus;
+
+SystemMediaControlsNotifier::SystemMediaControlsNotifier(
+    service_manager::Connector* connector)
+    : connector_(connector) {}
+
+SystemMediaControlsNotifier::~SystemMediaControlsNotifier() = default;
+
+void SystemMediaControlsNotifier::Initialize() {
+  // |service_| can be set in tests.
+  if (!service_)
+    service_ = system_media_controls::SystemMediaControlsService::GetInstance();
+
+  // |service_| can still be null if the current system does not support System
+  // Media Transport Controls.
+  if (!service_)
+    return;
+
+  // |connector_| can be null in tests.
+  if (!connector_)
+    return;
+
+  // Connect to the MediaControllerManager and create a MediaController that
+  // controls the active session so we can observe it.
+  media_session::mojom::MediaControllerManagerPtr controller_manager_ptr;
+  connector_->BindInterface(media_session::mojom::kServiceName,
+                            mojo::MakeRequest(&controller_manager_ptr));
+  controller_manager_ptr->CreateActiveMediaController(
+      mojo::MakeRequest(&media_controller_ptr_));
+
+  // Observe the active media controller for changes to playback state and
+  // supported actions.
+  media_session::mojom::MediaControllerObserverPtr media_controller_observer;
+  media_controller_observer_binding_.Bind(
+      mojo::MakeRequest(&media_controller_observer));
+  media_controller_ptr_->AddObserver(std::move(media_controller_observer));
+}
+
+void SystemMediaControlsNotifier::MediaSessionInfoChanged(
+    media_session::mojom::MediaSessionInfoPtr session_info) {
+  DCHECK(service_);
+
+  session_info_ = std::move(session_info);
+  if (session_info_) {
+    if (session_info_->playback_state ==
+        media_session::mojom::MediaPlaybackState::kPlaying) {
+      service_->SetPlaybackStatus(
+          MediaPlaybackStatus::MediaPlaybackStatus_Playing);
+    } else {
+      service_->SetPlaybackStatus(
+          MediaPlaybackStatus::MediaPlaybackStatus_Paused);
+    }
+  } else {
+    service_->SetPlaybackStatus(
+        MediaPlaybackStatus::MediaPlaybackStatus_Stopped);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/media/system_media_controls_notifier.h b/content/browser/media/system_media_controls_notifier.h
new file mode 100644
index 0000000..ed7bc8e
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier.h
@@ -0,0 +1,73 @@
+// 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 CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
+#define CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
+
+#include <memory>
+#include <vector>
+
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/media_session/public/mojom/media_controller.mojom.h"
+
+namespace system_media_controls {
+class SystemMediaControlsService;
+}  // namespace system_media_controls
+
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
+
+namespace content {
+
+// The SystemMediaControlsNotifier connects to Window's "System Media Transport
+// Controls" and keeps the OS informed of the current media playstate and
+// metadata. It observes changes to the active Media Session and updates the
+// SMTC accordingly.
+class CONTENT_EXPORT SystemMediaControlsNotifier
+    : public media_session::mojom::MediaControllerObserver {
+ public:
+  explicit SystemMediaControlsNotifier(service_manager::Connector* connector);
+  ~SystemMediaControlsNotifier() override;
+
+  void Initialize();
+
+  // media_session::mojom::MediaControllerObserver implementation.
+  void MediaSessionInfoChanged(
+      media_session::mojom::MediaSessionInfoPtr session_info) override;
+  void MediaSessionMetadataChanged(
+      const base::Optional<media_session::MediaMetadata>& metadata) override {}
+  void MediaSessionActionsChanged(
+      const std::vector<media_session::mojom::MediaSessionAction>& actions)
+      override {}
+  void MediaSessionChanged(
+      const base::Optional<base::UnguessableToken>& request_id) override {}
+
+  void SetSystemMediaControlsServiceForTesting(
+      system_media_controls::SystemMediaControlsService* service) {
+    service_ = service;
+  }
+
+ private:
+  // Our connection to Window's System Media Transport Controls.
+  system_media_controls::SystemMediaControlsService* service_ = nullptr;
+
+  // used to connect to the Media Session service.
+  service_manager::Connector* connector_;
+
+  // Tracks current media session state/metadata.
+  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  media_session::mojom::MediaSessionInfoPtr session_info_;
+
+  // Used to receive updates to the active media controller.
+  mojo::Binding<media_session::mojom::MediaControllerObserver>
+      media_controller_observer_binding_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsNotifier);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
diff --git a/content/browser/media/system_media_controls_notifier_unittest.cc b/content/browser/media/system_media_controls_notifier_unittest.cc
new file mode 100644
index 0000000..ab90552
--- /dev/null
+++ b/content/browser/media/system_media_controls_notifier_unittest.cc
@@ -0,0 +1,84 @@
+// 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 "content/browser/media/system_media_controls_notifier.h"
+
+#include <memory>
+#include <utility>
+
+#include "services/media_session/public/mojom/media_session.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+namespace content {
+
+using ABI::Windows::Media::MediaPlaybackStatus;
+using media_session::mojom::MediaPlaybackState;
+using media_session::mojom::MediaSessionInfo;
+using media_session::mojom::MediaSessionInfoPtr;
+using testing::Expectation;
+
+class SystemMediaControlsNotifierTest : public testing::Test {
+ public:
+  SystemMediaControlsNotifierTest() = default;
+  ~SystemMediaControlsNotifierTest() override = default;
+
+  void SetUp() override {
+    notifier_ =
+        std::make_unique<SystemMediaControlsNotifier>(/*connector=*/nullptr);
+    notifier_->SetSystemMediaControlsServiceForTesting(
+        &mock_system_media_controls_service_);
+    notifier_->Initialize();
+  }
+
+ protected:
+  void SimulatePlaying() {
+    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
+    session_info->playback_state = MediaPlaybackState::kPlaying;
+    notifier_->MediaSessionInfoChanged(std::move(session_info));
+  }
+
+  void SimulatePaused() {
+    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
+    session_info->playback_state = MediaPlaybackState::kPaused;
+    notifier_->MediaSessionInfoChanged(std::move(session_info));
+  }
+
+  void SimulateStopped() { notifier_->MediaSessionInfoChanged(nullptr); }
+
+  SystemMediaControlsNotifier& notifier() { return *notifier_; }
+  system_media_controls::testing::MockSystemMediaControlsService&
+  mock_system_media_controls_service() {
+    return mock_system_media_controls_service_;
+  }
+
+ private:
+  std::unique_ptr<SystemMediaControlsNotifier> notifier_;
+  system_media_controls::testing::MockSystemMediaControlsService
+      mock_system_media_controls_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsNotifierTest);
+};
+
+TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesPlaybackState) {
+  Expectation playing = EXPECT_CALL(
+      mock_system_media_controls_service(),
+      SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Playing));
+  Expectation paused =
+      EXPECT_CALL(
+          mock_system_media_controls_service(),
+          SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Paused))
+          .After(playing);
+  EXPECT_CALL(
+      mock_system_media_controls_service(),
+      SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Stopped))
+      .After(paused);
+
+  SimulatePlaying();
+  SimulatePaused();
+  SimulateStopped();
+}
+
+}  // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 71b64ff..18455585 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2129,10 +2129,12 @@
     }
   }
   if (is_win) {
+    sources += [ "../browser/media/system_media_controls_notifier_unittest.cc" ]
     deps += [
       "//third_party/blink/public/common",
       "//third_party/blink/public/common:font_unique_name_table_proto",
       "//third_party/iaccessible2",
+      "//ui/base/win/system_media_controls:test_support",
     ]
     libs = [
       "dwrite.lib",
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 67cfa13..49f1ed3 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -351,6 +351,8 @@
       "accelerators/global_media_keys_listener_win.cc",
       "accelerators/global_media_keys_listener_win.h",
       "accelerators/media_keys_listener_win.cc",
+      "accelerators/system_media_controls_media_keys_listener.cc",
+      "accelerators/system_media_controls_media_keys_listener.h",
     ]
   } else if (use_mpris) {
     sources += [
@@ -445,6 +447,10 @@
     }
   }
 
+  if (is_win) {
+    deps += [ "//ui/base/win/system_media_controls" ]
+  }
+
   if (use_mpris) {
     deps += [
       "//dbus",
@@ -1001,10 +1007,13 @@
 
   if (is_win) {
     sources += [
+      "accelerators/system_media_controls_media_keys_listener_unittest.cc",
       "dragdrop/os_exchange_data_win_unittest.cc",
       "win/hwnd_subclass_unittest.cc",
     ]
 
+    deps += [ "//ui/base/win/system_media_controls:test_support" ]
+
     ldflags = [
       "/DELAYLOAD:d2d1.dll",
       "/DELAYLOAD:d3d10_1.dll",
diff --git a/ui/base/accelerators/media_keys_listener_win.cc b/ui/base/accelerators/media_keys_listener_win.cc
index 5a24b96..c50ea0c 100644
--- a/ui/base/accelerators/media_keys_listener_win.cc
+++ b/ui/base/accelerators/media_keys_listener_win.cc
@@ -5,6 +5,7 @@
 #include "ui/base/accelerators/media_keys_listener.h"
 
 #include "ui/base/accelerators/global_media_keys_listener_win.h"
+#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
 
 namespace ui {
 
@@ -14,10 +15,18 @@
   DCHECK(delegate);
 
   if (scope == Scope::kGlobal) {
-    if (!GlobalMediaKeysListenerWin::has_instance())
+    // We should never have more than one global media keys listener.
+    if (!SystemMediaControlsMediaKeysListener::has_instance() &&
+        !GlobalMediaKeysListenerWin::has_instance()) {
+      auto listener =
+          std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
+      if (listener->Initialize())
+        return listener;
+
+      // If |Initialize()| fails, then we fall back to the
+      // GlobalMediaKeysListenerWin.
       return std::make_unique<GlobalMediaKeysListenerWin>(delegate);
-    // We shouldn't try to create more than one GlobalMediaKeysListenerWin
-    // instance.
+    }
     NOTREACHED();
   }
   return nullptr;
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
new file mode 100644
index 0000000..a07e0eb
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
@@ -0,0 +1,136 @@
+// 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 "ui/base/accelerators/system_media_controls_media_keys_listener.h"
+
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace ui {
+
+// static
+bool SystemMediaControlsMediaKeysListener::has_instance_ = false;
+
+SystemMediaControlsMediaKeysListener::SystemMediaControlsMediaKeysListener(
+    MediaKeysListener::Delegate* delegate)
+    : delegate_(delegate) {
+  DCHECK(delegate_);
+  DCHECK(!has_instance_);
+  has_instance_ = true;
+}
+
+SystemMediaControlsMediaKeysListener::~SystemMediaControlsMediaKeysListener() {
+  DCHECK(has_instance_);
+  has_instance_ = false;
+}
+
+bool SystemMediaControlsMediaKeysListener::Initialize() {
+  // |service_| can be set for tests.
+  if (!service_)
+    service_ = system_media_controls::SystemMediaControlsService::GetInstance();
+
+  // If we still don't have a service, then that means the
+  // SystemMediaControlsService failed to connect to the
+  // SystemMediaTransportControls. If that's the case, return false.
+  if (!service_)
+    return false;
+
+  service_->AddObserver(this);
+  return true;
+}
+
+bool SystemMediaControlsMediaKeysListener::StartWatchingMediaKey(
+    KeyboardCode key_code) {
+  DCHECK(IsMediaKeycode(key_code));
+
+  // If we're already listening for this key, do nothing.
+  if (key_codes_.contains(key_code))
+    return true;
+
+  key_codes_.insert(key_code);
+
+  DCHECK(service_);
+
+  switch (key_code) {
+    case VKEY_MEDIA_PLAY_PAUSE:
+      service_->SetIsPlayEnabled(true);
+      service_->SetIsPauseEnabled(true);
+      break;
+    case VKEY_MEDIA_NEXT_TRACK:
+      service_->SetIsNextEnabled(true);
+      break;
+    case VKEY_MEDIA_PREV_TRACK:
+      service_->SetIsPreviousEnabled(true);
+      break;
+    case VKEY_MEDIA_STOP:
+      service_->SetIsStopEnabled(true);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  return true;
+}
+
+void SystemMediaControlsMediaKeysListener::StopWatchingMediaKey(
+    KeyboardCode key_code) {
+  DCHECK(IsMediaKeycode(key_code));
+
+  // If we're not currently listening for this key, do nothing.
+  if (!key_codes_.contains(key_code))
+    return;
+
+  key_codes_.erase(key_code);
+
+  DCHECK(service_);
+
+  switch (key_code) {
+    case VKEY_MEDIA_PLAY_PAUSE:
+      service_->SetIsPlayEnabled(false);
+      service_->SetIsPauseEnabled(false);
+      break;
+    case VKEY_MEDIA_NEXT_TRACK:
+      service_->SetIsNextEnabled(false);
+      break;
+    case VKEY_MEDIA_PREV_TRACK:
+      service_->SetIsPreviousEnabled(false);
+      break;
+    case VKEY_MEDIA_STOP:
+      service_->SetIsStopEnabled(false);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void SystemMediaControlsMediaKeysListener::OnNext() {
+  MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPrevious() {
+  MaybeSendKeyCode(VKEY_MEDIA_PREV_TRACK);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPause() {
+  MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+}
+
+void SystemMediaControlsMediaKeysListener::OnStop() {
+  MaybeSendKeyCode(VKEY_MEDIA_STOP);
+}
+
+void SystemMediaControlsMediaKeysListener::OnPlay() {
+  MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
+}
+
+void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
+    KeyboardCode key_code) {
+  if (!key_codes_.contains(key_code))
+    return;
+
+  Accelerator accelerator(key_code, /*modifiers=*/0);
+  delegate_->OnMediaKeysAccelerator(accelerator);
+}
+
+}  // namespace ui
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.h b/ui/base/accelerators/system_media_controls_media_keys_listener.h
new file mode 100644
index 0000000..c900d841
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener.h
@@ -0,0 +1,69 @@
+// 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 UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
+#define UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
+
+#include "base/containers/flat_set.h"
+#include "ui/base/accelerators/media_keys_listener.h"
+#include "ui/base/ui_base_export.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace system_media_controls {
+class SystemMediaControlsService;
+}  // namespace system_media_controls
+
+namespace ui {
+
+// Implementation of MediaKeysListener that uses the System Media Transport
+// Controls API to listen for media key presses. It only allows for a single
+// instance to be created in order to prevent conflicts from multiple listeners.
+class UI_BASE_EXPORT SystemMediaControlsMediaKeysListener
+    : public MediaKeysListener,
+      public system_media_controls::SystemMediaControlsServiceObserver {
+ public:
+  explicit SystemMediaControlsMediaKeysListener(
+      MediaKeysListener::Delegate* delegate);
+  ~SystemMediaControlsMediaKeysListener() override;
+
+  static bool has_instance() { return has_instance_; }
+
+  bool Initialize();
+
+  // MediaKeysListener implementation.
+  bool StartWatchingMediaKey(KeyboardCode key_code) override;
+  void StopWatchingMediaKey(KeyboardCode key_code) override;
+
+  // system_media_controls::SystemMediaControlsServiceObserver implementation.
+  void OnNext() override;
+  void OnPrevious() override;
+  void OnPause() override;
+  void OnStop() override;
+  void OnPlay() override;
+
+  void SetSystemMediaControlsServiceForTesting(
+      system_media_controls::SystemMediaControlsService* service) {
+    service_ = service;
+  }
+
+ private:
+  static bool has_instance_;
+
+  // Sends the key code to the delegate if the delegate has asked for it.
+  void MaybeSendKeyCode(KeyboardCode key_code);
+
+  MediaKeysListener::Delegate* delegate_;
+
+  // Set of keys codes that we're currently listening for.
+  base::flat_set<KeyboardCode> key_codes_;
+
+  system_media_controls::SystemMediaControlsService* service_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListener);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_ACCELERATORS_SYSTEM_MEDIA_CONTROLS_MEDIA_KEYS_LISTENER_H_
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
new file mode 100644
index 0000000..b07c9a59
--- /dev/null
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
@@ -0,0 +1,135 @@
+// 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 "ui/base/accelerators/system_media_controls_media_keys_listener.h"
+
+#include <memory>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+using testing::_;
+using testing::Expectation;
+using testing::WithArg;
+
+namespace ui {
+
+namespace {
+
+class MockMediaKeysListenerDelegate : public MediaKeysListener::Delegate {
+ public:
+  MockMediaKeysListenerDelegate() = default;
+  ~MockMediaKeysListenerDelegate() override = default;
+
+  // MediaKeysListener::Delegate implementation.
+  MOCK_METHOD1(OnMediaKeysAccelerator, void(const Accelerator& accelerator));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate);
+};
+
+}  // anonymous namespace
+
+class SystemMediaControlsMediaKeysListenerTest : public testing::Test {
+ public:
+  SystemMediaControlsMediaKeysListenerTest() {
+    listener_ =
+        std::make_unique<SystemMediaControlsMediaKeysListener>(&delegate_);
+    listener_->SetSystemMediaControlsServiceForTesting(
+        &mock_system_media_controls_service_);
+  }
+
+  ~SystemMediaControlsMediaKeysListenerTest() override = default;
+
+ protected:
+  system_media_controls::testing::MockSystemMediaControlsService&
+  mock_system_media_controls_service() {
+    return mock_system_media_controls_service_;
+  }
+  MockMediaKeysListenerDelegate& delegate() { return delegate_; }
+  SystemMediaControlsMediaKeysListener* listener() { return listener_.get(); }
+
+ private:
+  system_media_controls::testing::MockSystemMediaControlsService
+      mock_system_media_controls_service_;
+  MockMediaKeysListenerDelegate delegate_;
+  std::unique_ptr<SystemMediaControlsMediaKeysListener> listener_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListenerTest);
+};
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest,
+       ListensToSystemMediaControlsService) {
+  EXPECT_CALL(mock_system_media_controls_service(), AddObserver(listener()));
+  listener()->Initialize();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, SimplePlayPauseTest) {
+  // Should be set to true when we start listening for the key.
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
+      .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
+        EXPECT_EQ(ui::VKEY_MEDIA_PLAY_PAUSE, accelerator.key_code());
+      }));
+
+  ASSERT_TRUE(listener()->Initialize());
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+
+  // Simulate media key press.
+  listener()->OnPlay();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, KeyCanBeReRegistered) {
+  Expectation enable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true));
+  Expectation disable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(false))
+          .After(enable_next);
+  Expectation reenable_next =
+      EXPECT_CALL(mock_system_media_controls_service(), SetIsNextEnabled(true))
+          .After(disable_next);
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
+      .After(reenable_next)
+      .WillOnce(WithArg<0>([](const Accelerator& accelerator) {
+        EXPECT_EQ(ui::VKEY_MEDIA_NEXT_TRACK, accelerator.key_code());
+      }));
+
+  ASSERT_TRUE(listener()->Initialize());
+
+  // Start listening to register the key.
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Stop listening to unregister the key.
+  listener()->StopWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Start listening to re-register the key.
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
+
+  // Simulate media key press.
+  listener()->OnNext();
+}
+
+TEST_F(SystemMediaControlsMediaKeysListenerTest, ListenForMultipleKeys) {
+  // Should be set to true when we start listening for the key.
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true));
+  EXPECT_CALL(mock_system_media_controls_service(), SetIsPreviousEnabled(true));
+
+  // Should receive the key presses.
+  EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(2);
+
+  ASSERT_TRUE(listener()->Initialize());
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
+  listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PREV_TRACK);
+
+  // Simulate media key press.
+  listener()->OnPlay();
+  listener()->OnPrevious();
+}
+
+}  // namespace ui
diff --git a/ui/base/win/system_media_controls/BUILD.gn b/ui/base/win/system_media_controls/BUILD.gn
new file mode 100644
index 0000000..41ca483
--- /dev/null
+++ b/ui/base/win/system_media_controls/BUILD.gn
@@ -0,0 +1,36 @@
+# 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.
+
+component("system_media_controls") {
+  sources = [
+    "system_media_controls_service.cc",
+    "system_media_controls_service.h",
+    "system_media_controls_service_impl.cc",
+    "system_media_controls_service_impl.h",
+    "system_media_controls_service_observer.cc",
+    "system_media_controls_service_observer.h",
+  ]
+
+  defines = [ "IS_SYSTEM_MEDIA_CONTROLS_IMPL" ]
+
+  deps = [
+    "//base",
+    "//ui/gfx",
+  ]
+}
+
+static_library("test_support") {
+  testonly = true
+
+  sources = [
+    "mock_system_media_controls_service.cc",
+    "mock_system_media_controls_service.h",
+  ]
+
+  deps = [
+    ":system_media_controls",
+    "//base",
+    "//testing/gmock",
+  ]
+}
diff --git a/ui/base/win/system_media_controls/OWNERS b/ui/base/win/system_media_controls/OWNERS
new file mode 100644
index 0000000..4152d74
--- /dev/null
+++ b/ui/base/win/system_media_controls/OWNERS
@@ -0,0 +1 @@
+steimel@chromium.org
\ No newline at end of file
diff --git a/ui/base/win/system_media_controls/mock_system_media_controls_service.cc b/ui/base/win/system_media_controls/mock_system_media_controls_service.cc
new file mode 100644
index 0000000..3f3e4bb
--- /dev/null
+++ b/ui/base/win/system_media_controls/mock_system_media_controls_service.cc
@@ -0,0 +1,17 @@
+// 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 "ui/base/win/system_media_controls/mock_system_media_controls_service.h"
+
+namespace system_media_controls {
+
+namespace testing {
+
+MockSystemMediaControlsService::MockSystemMediaControlsService() = default;
+
+MockSystemMediaControlsService::~MockSystemMediaControlsService() = default;
+
+}  // namespace testing
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/mock_system_media_controls_service.h b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
new file mode 100644
index 0000000..4f5c913
--- /dev/null
+++ b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
@@ -0,0 +1,44 @@
+// 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 UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+
+#include "base/macros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+namespace testing {
+
+// Mock implementation of SystemMediaControlsService for testing.
+class MockSystemMediaControlsService : public SystemMediaControlsService {
+ public:
+  MockSystemMediaControlsService();
+  ~MockSystemMediaControlsService() override;
+
+  // SystemMediaControlsService implementation.
+  MOCK_METHOD1(AddObserver, void(SystemMediaControlsServiceObserver* observer));
+  MOCK_METHOD1(RemoveObserver,
+               void(SystemMediaControlsServiceObserver* observer));
+  MOCK_METHOD1(SetIsNextEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPreviousEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPlayEnabled, void(bool value));
+  MOCK_METHOD1(SetIsPauseEnabled, void(bool value));
+  MOCK_METHOD1(SetIsStopEnabled, void(bool value));
+  MOCK_METHOD1(SetPlaybackStatus,
+               void(ABI::Windows::Media::MediaPlaybackStatus status));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSystemMediaControlsService);
+};
+
+}  // namespace testing
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_MOCK_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service.cc b/ui/base/win/system_media_controls/system_media_controls_service.cc
new file mode 100644
index 0000000..58d5a86
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service.cc
@@ -0,0 +1,22 @@
+// 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 "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+#include "ui/base/win/system_media_controls/system_media_controls_service_impl.h"
+
+namespace system_media_controls {
+
+// static
+SystemMediaControlsService* SystemMediaControlsService::GetInstance() {
+  internal::SystemMediaControlsServiceImpl* impl =
+      internal::SystemMediaControlsServiceImpl::GetInstance();
+  if (impl->Initialize())
+    return impl;
+  return nullptr;
+}
+
+SystemMediaControlsService::~SystemMediaControlsService() = default;
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service.h b/ui/base/win/system_media_controls/system_media_controls_service.h
new file mode 100644
index 0000000..fe66681
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service.h
@@ -0,0 +1,50 @@
+// 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 UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
+
+#include <windows.media.control.h>
+
+#include "base/component_export.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+// The SystemMediaControlsService connects with Windows's System Media Transport
+// Controls, receives media key events, and propagates those events to listening
+// SystemMediaControlsServiceObservers. The SystemMediaControlsService tells the
+// System Media Transport Controls which actions are currently available. The
+// SystemMediaControlsService is also used to keep the System Media Transport
+// Controls informed of the current media playback state and metadata.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsService {
+ public:
+  // Returns the singleton instance, creating if necessary. If the
+  // SystemMediaControlsService fails to connect to the
+  // SystemMediaTransportControls, this returns null.
+  static SystemMediaControlsService* GetInstance();
+
+  virtual void AddObserver(SystemMediaControlsServiceObserver* observer) = 0;
+  virtual void RemoveObserver(SystemMediaControlsServiceObserver* observer) = 0;
+
+  // TODO(steimel): Add other controls.
+  // Enable or disable specific controls.
+  virtual void SetIsNextEnabled(bool value) = 0;
+  virtual void SetIsPreviousEnabled(bool value) = 0;
+  virtual void SetIsPlayEnabled(bool value) = 0;
+  virtual void SetIsPauseEnabled(bool value) = 0;
+  virtual void SetIsStopEnabled(bool value) = 0;
+
+  // Setters for metadata.
+  virtual void SetPlaybackStatus(
+      ABI::Windows::Media::MediaPlaybackStatus status) = 0;
+
+ protected:
+  virtual ~SystemMediaControlsService();
+};
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.cc b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
new file mode 100644
index 0000000..9d7a1a4
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
@@ -0,0 +1,210 @@
+// 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 "ui/base/win/system_media_controls/system_media_controls_service_impl.h"
+
+#include <systemmediatransportcontrolsinterop.h>
+#include <windows.media.control.h>
+#include <wrl/client.h>
+#include <wrl/event.h>
+
+#include "base/strings/string_piece.h"
+#include "base/win/core_winrt_util.h"
+#include "base/win/scoped_hstring.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+
+namespace system_media_controls {
+
+namespace internal {
+
+using ABI::Windows::Media::ISystemMediaTransportControls;
+using ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs;
+using ABI::Windows::Media::SystemMediaTransportControls;
+using ABI::Windows::Media::SystemMediaTransportControlsButton;
+using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
+
+// static
+SystemMediaControlsServiceImpl* SystemMediaControlsServiceImpl::GetInstance() {
+  // We use a base::Singleton here instead of a base::NoDestruct so that we can
+  // clean up external listeners against the Windows platform at exit.
+  return base::Singleton<SystemMediaControlsServiceImpl>::get();
+}
+
+SystemMediaControlsServiceImpl::SystemMediaControlsServiceImpl() = default;
+
+SystemMediaControlsServiceImpl::~SystemMediaControlsServiceImpl() {
+  if (has_valid_registration_token_) {
+    DCHECK(system_media_controls_);
+    system_media_controls_->remove_ButtonPressed(registration_token_);
+    system_media_controls_->put_IsEnabled(false);
+  }
+}
+
+bool SystemMediaControlsServiceImpl::Initialize() {
+  if (attempted_to_initialize_)
+    return initialized_;
+
+  attempted_to_initialize_ = true;
+
+  if (!base::win::ResolveCoreWinRTDelayload() ||
+      !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) {
+    return false;
+  }
+
+  Microsoft::WRL::ComPtr<ISystemMediaTransportControlsInterop> interop;
+  HRESULT hr = base::win::GetActivationFactory<
+      ISystemMediaTransportControlsInterop,
+      RuntimeClass_Windows_Media_SystemMediaTransportControls>(&interop);
+  if (FAILED(hr))
+    return false;
+
+  hr = interop->GetForWindow(gfx::SingletonHwnd::GetInstance()->hwnd(),
+                             IID_PPV_ARGS(&system_media_controls_));
+  if (FAILED(hr))
+    return false;
+
+  auto handler =
+      Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<
+          SystemMediaTransportControls*,
+          SystemMediaTransportControlsButtonPressedEventArgs*>>(
+          &SystemMediaControlsServiceImpl::ButtonPressed);
+  hr = system_media_controls_->add_ButtonPressed(handler.Get(),
+                                                 &registration_token_);
+  if (FAILED(hr))
+    return false;
+
+  has_valid_registration_token_ = true;
+
+  hr = system_media_controls_->put_IsEnabled(true);
+  if (FAILED(hr))
+    return false;
+
+  initialized_ = true;
+  return true;
+}
+
+void SystemMediaControlsServiceImpl::AddObserver(
+    SystemMediaControlsServiceObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void SystemMediaControlsServiceImpl::RemoveObserver(
+    SystemMediaControlsServiceObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void SystemMediaControlsServiceImpl::SetIsNextEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsNextEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPreviousEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPreviousEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPlayEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPlayEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsPauseEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsPauseEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetIsStopEnabled(bool value) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_IsStopEnabled(value);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetPlaybackStatus(
+    ABI::Windows::Media::MediaPlaybackStatus status) {
+  DCHECK(initialized_);
+  HRESULT hr = system_media_controls_->put_PlaybackStatus(status);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::OnPlay() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPlay();
+}
+
+void SystemMediaControlsServiceImpl::OnPause() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPause();
+}
+
+void SystemMediaControlsServiceImpl::OnNext() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnNext();
+}
+
+void SystemMediaControlsServiceImpl::OnPrevious() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnPrevious();
+}
+
+void SystemMediaControlsServiceImpl::OnStop() {
+  for (SystemMediaControlsServiceObserver& obs : observers_)
+    obs.OnStop();
+}
+
+// static
+HRESULT SystemMediaControlsServiceImpl::ButtonPressed(
+    ISystemMediaTransportControls* sender,
+    ISystemMediaTransportControlsButtonPressedEventArgs* args) {
+  SystemMediaTransportControlsButton button;
+  HRESULT hr = args->get_Button(&button);
+  if (FAILED(hr))
+    return hr;
+
+  SystemMediaControlsServiceImpl* impl = GetInstance();
+
+  switch (button) {
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Play:
+      impl->OnPlay();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Pause:
+      impl->OnPause();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Next:
+      impl->OnNext();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Previous:
+      impl->OnPrevious();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Stop:
+      impl->OnStop();
+      break;
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Record:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_FastForward:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_Rewind:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_ChannelUp:
+    case SystemMediaTransportControlsButton::
+        SystemMediaTransportControlsButton_ChannelDown:
+      break;
+  }
+
+  return S_OK;
+}
+
+}  // namespace internal
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.h b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
new file mode 100644
index 0000000..fb10cde
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
@@ -0,0 +1,86 @@
+// 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 UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
+
+#include <windows.foundation.h>
+#include <windows.media.control.h>
+#include <wrl/client.h>
+
+#include "base/component_export.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list.h"
+#include "ui/base/win/system_media_controls/system_media_controls_service.h"
+
+namespace system_media_controls {
+
+class SystemMediaControlsServiceObserver;
+
+namespace internal {
+
+// Implementation of SystemMediaControlsService that actually connects to the
+// Windows's System Media Transport Controls.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceImpl
+    : public SystemMediaControlsService {
+ public:
+  SystemMediaControlsServiceImpl();
+  ~SystemMediaControlsServiceImpl() override;
+
+  static SystemMediaControlsServiceImpl* GetInstance();
+
+  // Connects to the SystemMediaTransportControls. Returns true if connection
+  // is successful. If already connected, does nothing and returns true.
+  bool Initialize();
+
+  // SystemMediaControlsService implementation.
+  void AddObserver(SystemMediaControlsServiceObserver* observer) override;
+  void RemoveObserver(SystemMediaControlsServiceObserver* observer) override;
+  void SetIsNextEnabled(bool value) override;
+  void SetIsPreviousEnabled(bool value) override;
+  void SetIsPlayEnabled(bool value) override;
+  void SetIsPauseEnabled(bool value) override;
+  void SetIsStopEnabled(bool value) override;
+  void SetPlaybackStatus(
+      ABI::Windows::Media::MediaPlaybackStatus status) override;
+
+ private:
+  friend struct base::DefaultSingletonTraits<SystemMediaControlsServiceImpl>;
+
+  static HRESULT ButtonPressed(
+      ABI::Windows::Media::ISystemMediaTransportControls* sender,
+      ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs*
+          args);
+
+  // Called by ButtonPressed when the particular key is pressed.
+  void OnPlay();
+  void OnPause();
+  void OnNext();
+  void OnPrevious();
+  void OnStop();
+
+  Microsoft::WRL::ComPtr<ABI::Windows::Media::ISystemMediaTransportControls>
+      system_media_controls_;
+  EventRegistrationToken registration_token_;
+
+  // True if we've already tried to connect to the SystemMediaTransportControls.
+  bool attempted_to_initialize_ = false;
+
+  // True if we've successfully registered a button handler on the
+  // SystemMediaTransportControls.
+  bool has_valid_registration_token_ = false;
+
+  // True if we've successfully connected to the SystemMediaTransportControls.
+  bool initialized_ = false;
+
+  base::ObserverList<SystemMediaControlsServiceObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsServiceImpl);
+};
+
+}  // namespace internal
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_IMPL_H_
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_observer.cc b/ui/base/win/system_media_controls/system_media_controls_service_observer.cc
new file mode 100644
index 0000000..cad848d
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_observer.cc
@@ -0,0 +1,12 @@
+// 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 "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+
+namespace system_media_controls {
+
+SystemMediaControlsServiceObserver::~SystemMediaControlsServiceObserver() =
+    default;
+
+}  // namespace system_media_controls
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_observer.h b/ui/base/win/system_media_controls/system_media_controls_service_observer.h
new file mode 100644
index 0000000..0f82420a
--- /dev/null
+++ b/ui/base/win/system_media_controls/system_media_controls_service_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 UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_
+#define UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_
+
+#include "base/component_export.h"
+#include "base/observer_list_types.h"
+
+namespace system_media_controls {
+
+// Interface to observe events on the SystemMediaControlsService.
+class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsServiceObserver
+    : public base::CheckedObserver {
+ public:
+  virtual void OnNext() = 0;
+  virtual void OnPrevious() = 0;
+  virtual void OnPause() = 0;
+  virtual void OnStop() = 0;
+  virtual void OnPlay() = 0;
+
+ protected:
+  ~SystemMediaControlsServiceObserver() override;
+};
+
+}  // namespace system_media_controls
+
+#endif  // UI_BASE_WIN_SYSTEM_MEDIA_CONTROLS_SYSTEM_MEDIA_CONTROLS_SERVICE_OBSERVER_H_