Commit ae7e6672 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Audio Focus] Apps should have separate group

Audio focus is currently grouped for media sessions
in the browser. Apps that are displayed in their
own window (e.g. PWAs, platform apps) should have
their own group id shared across all media sessions
for that app.

BUG=906285

Change-Id: I11004301f0e8c3118b62e4b25bcbfe15ecd351e4
Reviewed-on: https://chromium-review.googlesource.com/c/1344821
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarBen Wells <benwells@chromium.org>
Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612820}
parent e91e2538
......@@ -16,6 +16,8 @@ source_set("platform_apps") {
"app_termination_observer.h",
"app_window_registry_util.cc",
"app_window_registry_util.h",
"audio_focus_web_contents_observer.cc",
"audio_focus_web_contents_observer.h",
"browser_context_keyed_service_factories.cc",
"browser_context_keyed_service_factories.h",
"chrome_apps_browser_api_provider.cc",
......
// Copyright 2018 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 "chrome/browser/apps/platform_apps/audio_focus_web_contents_observer.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/media_session.h"
#include "content/public/browser/navigation_handle.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/extension.h"
namespace apps {
AudioFocusWebContentsObserver::AudioFocusWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {}
AudioFocusWebContentsObserver::~AudioFocusWebContentsObserver() = default;
void AudioFocusWebContentsObserver::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() ||
navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) {
return;
}
if (!audio_focus_group_id_.is_empty())
return;
content::BrowserContext* context =
navigation_handle->GetWebContents()->GetBrowserContext();
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(context)
->enabled_extensions()
.GetExtensionOrAppByURL(navigation_handle->GetURL());
if (!extension || !extension->is_platform_app())
return;
extensions::ProcessManager* pm = extensions::ProcessManager::Get(context);
extensions::ExtensionHost* host =
pm->GetBackgroundHostForExtension(extension->id());
DCHECK(host);
// If we are the background contents then we will generate a group id.
// Otherwise, we will use the group id from the background contents. This
// means that all web contents for an app will have the same group id. This
// will only be done once for a given web contents and expects it to not
// change platform app during its lifetime.
if (host->host_contents() == web_contents()) {
audio_focus_group_id_ = base::UnguessableToken::Create();
} else {
AudioFocusWebContentsObserver* observer =
AudioFocusWebContentsObserver::FromWebContents(host->host_contents());
DCHECK(observer);
audio_focus_group_id_ = observer->audio_focus_group_id_;
}
content::MediaSession::Get(web_contents())
->SetAudioFocusGroupId(audio_focus_group_id_);
}
} // namespace apps
// Copyright 2018 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_APPS_PLATFORM_APPS_AUDIO_FOCUS_WEB_CONTENTS_OBSERVER_H_
#define CHROME_BROWSER_APPS_PLATFORM_APPS_AUDIO_FOCUS_WEB_CONTENTS_OBSERVER_H_
#include "base/macros.h"
#include "base/unguessable_token.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace apps {
// AudioFocusWebContentsObserver manages audio focus group ids for apps. This
// means that apps will have seperate audio focus from the browser.
class AudioFocusWebContentsObserver
: public content::WebContentsObserver,
public content::WebContentsUserData<AudioFocusWebContentsObserver> {
public:
~AudioFocusWebContentsObserver() override;
private:
friend class content::WebContentsUserData<AudioFocusWebContentsObserver>;
friend class AudioFocusWebContentsObserver;
friend class AudioFocusWebContentsObserverBrowserTest;
explicit AudioFocusWebContentsObserver(content::WebContents*);
// content::WebContentsObserver overrides.
void DidFinishNavigation(content::NavigationHandle*) override;
// The audio focus group id is used to group media sessions together for apps.
base::UnguessableToken audio_focus_group_id_ = base::UnguessableToken::Null();
DISALLOW_COPY_AND_ASSIGN(AudioFocusWebContentsObserver);
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_PLATFORM_APPS_AUDIO_FOCUS_WEB_CONTENTS_OBSERVER_H_
// Copyright 2018 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 "base/macros.h"
#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
#include "chrome/browser/apps/platform_apps/audio_focus_web_contents_observer.h"
#include "extensions/test/extension_test_message_listener.h"
namespace apps {
// AudioFocusWebContentsObserverBrowserTest test that apps have separate audio
// focus from the rest of the browser.
class AudioFocusWebContentsObserverBrowserTest
: public extensions::PlatformAppBrowserTest {
public:
AudioFocusWebContentsObserverBrowserTest() = default;
~AudioFocusWebContentsObserverBrowserTest() override = default;
const base::UnguessableToken& GetAudioFocusGroupId(
content::WebContents* web_contents) {
AudioFocusWebContentsObserver* wco =
AudioFocusWebContentsObserver::FromWebContents(web_contents);
return wco->audio_focus_group_id_;
}
private:
DISALLOW_COPY_AND_ASSIGN(AudioFocusWebContentsObserverBrowserTest);
};
IN_PROC_BROWSER_TEST_F(AudioFocusWebContentsObserverBrowserTest,
PlatformAppHasDifferentAudioFocus) {
ASSERT_TRUE(embedded_test_server()->Start());
ExtensionTestMessageListener launched_listener("Launched", false);
const extensions::Extension* extension =
InstallAndLaunchPlatformApp("minimal");
ASSERT_TRUE(extension);
EXPECT_TRUE(extension->is_platform_app());
// Wait for the extension to tell us it's initialized its context menus and
// launched a window.
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
// Get the web contents and make sure it has a group id.
content::WebContents* web_contents = GetFirstAppWindowWebContents();
EXPECT_TRUE(web_contents);
EXPECT_NE(base::UnguessableToken::Null(), GetAudioFocusGroupId(web_contents));
// Create a new window and navigate it to the test app.
ExtensionTestMessageListener new_launched_listener("Launched", false);
LaunchPlatformApp(extension);
ASSERT_TRUE(new_launched_listener.WaitUntilSatisfied());
// Ensure the new window has the same group id.
content::WebContents* new_contents = GetFirstAppWindowWebContents();
EXPECT_TRUE(new_contents);
EXPECT_NE(web_contents, new_contents);
EXPECT_EQ(GetAudioFocusGroupId(web_contents),
GetAudioFocusGroupId(new_contents));
}
} // namespace apps
......@@ -8,6 +8,7 @@
#include <string>
#include "base/lazy_instance.h"
#include "chrome/browser/apps/platform_apps/audio_focus_web_contents_observer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/data_use_measurement/data_use_web_contents_observer.h"
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
......@@ -49,6 +50,7 @@ void ChromeExtensionHostDelegate::OnExtensionHostCreated(
data_use_measurement::DataUseWebContentsObserver::CreateForWebContents(
web_contents);
PrefsTabHelper::CreateForWebContents(web_contents);
apps::AudioFocusWebContentsObserver::CreateForWebContents(web_contents);
}
void ChromeExtensionHostDelegate::OnRenderViewCreatedForBackgroundPage(
......
......@@ -11,6 +11,7 @@
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/apps/platform_apps/audio_focus_web_contents_observer.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/data_use_measurement/data_use_web_contents_observer.h"
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
......@@ -213,6 +214,8 @@ void ChromeAppDelegate::InitWebContents(content::WebContents* web_contents) {
extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
web_contents);
apps::AudioFocusWebContentsObserver::CreateForWebContents(web_contents);
zoom::ZoomController::CreateForWebContents(web_contents);
}
......
......@@ -1239,6 +1239,7 @@ test("browser_tests") {
"../browser/apps/platform_apps/api/sync_file_system/sync_file_system_browsertest.cc",
"../browser/apps/platform_apps/app_browsertest_util.cc",
"../browser/apps/platform_apps/app_browsertest_util.h",
"../browser/apps/platform_apps/audio_focus_web_contents_observer_browsertest.cc",
"../browser/extensions/active_tab_apitest.cc",
"../browser/extensions/activity_log/activity_log_browsertest.cc",
"../browser/extensions/alert_apitest.cc",
......
......@@ -46,6 +46,7 @@ class MockMediaSession : public content::MediaSession {
MOCK_METHOD1(GetDebugInfo, void(GetDebugInfoCallback));
MOCK_METHOD0(PreviousTrack, void());
MOCK_METHOD0(NextTrack, void());
MOCK_METHOD1(SetAudioFocusGroupId, void(const base::UnguessableToken&));
private:
DISALLOW_COPY_AND_ASSIGN(MockMediaSession);
......
......@@ -204,7 +204,7 @@ class MediaSessionImpl : public MediaSession,
// group can share audio focus. Setting this to null will use the browser
// default value.
CONTENT_EXPORT void SetAudioFocusGroupId(
const base::UnguessableToken& group_id);
const base::UnguessableToken& group_id) override;
// Suspend the media session.
// |type| represents the origin of the request.
......
......@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "content/common/content_export.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
......@@ -46,6 +47,12 @@ class MediaSession : public media_session::mojom::MediaSession {
// Set the volume multiplier applied during ducking.
virtual void SetDuckingVolumeMultiplier(double multiplier) = 0;
// Set the audio focus group id for this media session. Sessions in the same
// group can share audio focus. Setting this to null will use the browser
// default value. This will only have any effect if audio focus grouping is
// supported.
virtual void SetAudioFocusGroupId(const base::UnguessableToken& group_id) = 0;
// media_session.mojom.MediaSession overrides -------------------------------
// Suspend the media session.
......
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