blob: 7e1afa9efc7ce6c96abb92193ef577667f0effd7 [file] [log] [blame]
// Copyright (c) 2021 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 <memory>
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/test/thread_test_helper.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/extension.h"
using extensions::Extension;
namespace {
bool AccessingCamera(Profile* profile, const std::string& app_id) {
auto accessing_camera = apps::mojom::OptionalBool::kUnknown;
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
proxy->FlushMojoCallsForTesting();
proxy->AppCapabilityAccessCache().ForOneApp(
app_id, [&accessing_camera](const apps::CapabilityAccessUpdate& update) {
accessing_camera = update.Camera();
});
return accessing_camera == apps::mojom::OptionalBool::kTrue;
}
bool AccessingMicrophone(Profile* profile, const std::string& app_id) {
auto accessing_microphone = apps::mojom::OptionalBool::kUnknown;
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
proxy->FlushMojoCallsForTesting();
proxy->AppCapabilityAccessCache().ForOneApp(
app_id,
[&accessing_microphone](const apps::CapabilityAccessUpdate& update) {
accessing_microphone = update.Microphone();
});
return accessing_microphone == apps::mojom::OptionalBool::kTrue;
}
class FakeMediaObserver : public MediaCaptureDevicesDispatcher::Observer {
public:
explicit FakeMediaObserver(base::OnceClosure done_closure)
: done_closure_(std::move(done_closure)) {
media_dispatcher_.Observe(MediaCaptureDevicesDispatcher::GetInstance());
}
~FakeMediaObserver() override = default;
// MediaCaptureDevicesDispatcher::Observer:
void OnRequestUpdate(int render_process_id,
int render_frame_id,
blink::mojom::MediaStreamType stream_type,
const content::MediaRequestState state) override {
if (!done_closure_.is_null())
std::move(done_closure_).Run();
content::RunAllTasksUntilIdle();
}
private:
base::OnceClosure done_closure_;
base::ScopedObservation<MediaCaptureDevicesDispatcher,
MediaCaptureDevicesDispatcher::Observer>
media_dispatcher_{this};
};
void MediaRequestChange(int render_process_id,
int render_frame_id,
const GURL& url,
blink::mojom::MediaStreamType stream_type,
content::MediaRequestState state) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
base::RunLoop run_loop;
FakeMediaObserver fake_observer(run_loop.QuitClosure());
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&MediaRequestChange, render_process_id,
render_frame_id, url, stream_type, state));
run_loop.Run();
content::RunAllTasksUntilIdle();
return;
}
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
MediaCaptureDevicesDispatcher::GetInstance()->OnMediaRequestStateChanged(
render_process_id, render_frame_id, 0, url, stream_type, state);
}
void MediaRequestChangeForWebContent(content::WebContents* web_content,
const GURL& url,
blink::mojom::MediaStreamType stream_type,
content::MediaRequestState state) {
ASSERT_TRUE(web_content);
MediaRequestChange(web_content->GetMainFrame()->GetProcess()->GetID(),
web_content->GetMainFrame()->GetRoutingID(), url,
stream_type, state);
}
} // namespace
class MediaAccessExtensionAppsTest : public extensions::PlatformAppBrowserTest {
public:
void SetUpOnMainThread() override {
extensions::PlatformAppBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
}
void UninstallApp(const std::string& app_id) {
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
proxy->UninstallSilently(app_id, apps::mojom::UninstallSource::kAppList);
proxy->FlushMojoCallsForTesting();
}
GURL GetUrl1() {
return embedded_test_server()->GetURL("app.com", "/ssl/google.html");
}
GURL GetUrl2() {
return embedded_test_server()->GetURL("app.com", "/google/google.html");
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
base::WeakPtr<MediaAccessExtensionAppsTest> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<MediaAccessExtensionAppsTest> weak_ptr_factory_{this};
};
IN_PROC_BROWSER_TEST_F(MediaAccessExtensionAppsTest,
RequestAccessingForChromeInTabs) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl1()));
content::WebContents* web_content1 = GetWebContents();
// Request accessing the camera for |web_content1|.
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
AddBlankTabAndShow(browser());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl2()));
content::WebContents* web_content2 = GetWebContents();
// Request accessing the microphone for |web_content2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Stop accessing the camera for |web_content1|.
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Stop accessing the microphone for |web_content2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
}
IN_PROC_BROWSER_TEST_F(MediaAccessExtensionAppsTest,
RequestAccessingForChromeInNewBrowsers) {
Browser* browser1 =
Browser::Create(Browser::CreateParams(browser()->profile(), true));
ASSERT_TRUE(browser1);
ASSERT_NE(browser(), browser1);
AddBlankTabAndShow(browser1);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser1, GetUrl1()));
content::WebContents* web_content1 =
browser1->tab_strip_model()->GetActiveWebContents();
int render_process_id1 = web_content1->GetMainFrame()->GetProcess()->GetID();
int render_frame_id1 = web_content1->GetMainFrame()->GetRoutingID();
// Request accessing the camera and the microphone for |web_content1|.
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
AddBlankTabAndShow(browser1);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser1, GetUrl2()));
content::WebContents* web_content2 =
browser1->tab_strip_model()->GetActiveWebContents();
int render_process_id2 = web_content2->GetMainFrame()->GetProcess()->GetID();
int render_frame_id2 = web_content2->GetMainFrame()->GetRoutingID();
// Request accessing the camera and the microphone for |web_content2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content2, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Close the tab for |web_content2|.
browser1->tab_strip_model()->CloseSelectedTabs();
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
MediaRequestChange(render_process_id2, render_frame_id2, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
MediaRequestChange(render_process_id2, render_frame_id2, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_TRUE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Close the tab for |web_content1|.
browser1->tab_strip_model()->CloseSelectedTabs();
EXPECT_FALSE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
MediaRequestChange(render_process_id1, render_frame_id1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
MediaRequestChange(render_process_id1, render_frame_id1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
}
IN_PROC_BROWSER_TEST_F(MediaAccessExtensionAppsTest,
RequestAccessingForPlatformApp) {
const Extension* extension =
LoadAndLaunchPlatformApp("context_menu", "Launched");
ASSERT_TRUE(extension);
content::WebContents* web_contents = GetFirstAppWindowWebContents();
ASSERT_TRUE(web_contents);
// Request accessing the camera for |web_contents|.
MediaRequestChangeForWebContent(
web_contents, web_contents->GetLastCommittedURL(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), extension->id()));
// Request accessing the microphone for |web_contents|.
MediaRequestChangeForWebContent(
web_contents, web_contents->GetLastCommittedURL(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), extension->id()));
// Stop accessing the microphone for |web_contents|.
MediaRequestChangeForWebContent(
web_contents, web_contents->GetLastCommittedURL(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_TRUE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), extension->id()));
// Stop accessing the camera for |web_contents|.
MediaRequestChangeForWebContent(
web_contents, web_contents->GetLastCommittedURL(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), extension->id()));
}
IN_PROC_BROWSER_TEST_F(MediaAccessExtensionAppsTest,
RequestAccessingForHostApp) {
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("app1"));
ASSERT_TRUE(extension);
// Navigate to the app's launch URL.
auto url = extensions::AppLaunchInfo::GetLaunchWebURL(extension);
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
content::WebContents* web_content1 =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_content1);
// Request accessing the camera and microphone for |web_contents|.
MediaRequestChangeForWebContent(
web_content1, url, blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content1, url, blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), extension->id()));
AddBlankTabAndShow(browser());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl1()));
content::WebContents* web_content2 = GetWebContents();
// Request accessing the camera for |web_content2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), extension->id()));
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), extension->id()));
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Uninstall the app.
std::string app_id = extension->id();
UninstallApp(app_id);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
EXPECT_TRUE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
// Request accessing the camera for |web_content2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
EXPECT_FALSE(
AccessingCamera(browser()->profile(), extension_misc::kChromeAppId));
EXPECT_FALSE(
AccessingMicrophone(browser()->profile(), extension_misc::kChromeAppId));
}
class MediaAccessWebAppsTest : public web_app::WebAppControllerBrowserTest {
public:
MediaAccessWebAppsTest() = default;
~MediaAccessWebAppsTest() override = default;
std::string CreateWebApp(const GURL& url) const {
auto web_app_info = std::make_unique<WebApplicationInfo>();
web_app_info->start_url = url;
web_app_info->scope = url;
return web_app::test::InstallWebApp(browser()->profile(),
std::move(web_app_info));
}
void UninstallWebApp(const std::string& app_id) const {
web_app::UninstallWebApp(browser()->profile(), app_id);
apps::AppServiceProxyFactory::GetForProfile(browser()->profile())
->FlushMojoCallsForTesting();
}
GURL GetUrl1() {
return https_server()->GetURL("app.com", "/ssl/google.html");
}
GURL GetUrl2() {
return https_server()->GetURL("app.com", "/google/google.html");
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
base::WeakPtr<MediaAccessWebAppsTest> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<MediaAccessWebAppsTest> weak_ptr_factory_{this};
};
IN_PROC_BROWSER_TEST_F(MediaAccessWebAppsTest, RequestAccessingCamera) {
std::string app_id = CreateWebApp(GetUrl1());
// Launch |app_id| in a new tab.
web_app::LaunchWebAppBrowser(browser()->profile(), app_id);
web_app::NavigateToURLAndWait(browser(), GetUrl1());
// Request accessing the camera for |app_id| in the new tab.
content::WebContents* web_content1 = GetWebContents();
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id));
// Launch |app_id| in a new window.
content::WebContents* web_content2 = OpenApplication(app_id);
Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
ASSERT_TRUE(app_browser);
ASSERT_NE(browser(), app_browser);
// Request accessing the camera for |app_id| in the new window.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id));
// Stop accessing the camera for |app_id| in the tab.
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id));
// Stop accessing the camera for |app_id| in the window.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
web_app::CloseAndWait(app_browser);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
web_app::CloseAndWait(browser());
}
// TODO(crbug.com/1178664) Disabled due to flake.
IN_PROC_BROWSER_TEST_F(MediaAccessWebAppsTest,
DISABLED_RequestAccessingMicrophone) {
std::string app_id = CreateWebApp(GetUrl1());
// Launch |app_id| in a new tab.
web_app::LaunchWebAppBrowser(browser()->profile(), app_id);
web_app::NavigateToURLAndWait(browser(), GetUrl1());
// Request accessing the camera for |app_id| in the new tab.
content::WebContents* web_content1 = GetWebContents();
int render_process_id1 = web_content1->GetMainFrame()->GetProcess()->GetID();
int render_frame_id1 = web_content1->GetMainFrame()->GetRoutingID();
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id));
// Launch |app_id| in a new window.
content::WebContents* web_content2 = OpenApplication(app_id);
int render_process_id2 = web_content2->GetMainFrame()->GetProcess()->GetID();
int render_frame_id2 = web_content2->GetMainFrame()->GetRoutingID();
Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
ASSERT_TRUE(app_browser);
ASSERT_NE(browser(), app_browser);
// Request accessing the camera for |app_id| in the new window.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id));
// Close browsers.
web_app::CloseAndWait(app_browser);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id));
// Stop accessing the camera for |app_id| in the tab.
MediaRequestChange(render_process_id1, render_frame_id1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
// Stop accessing the camera for |app_id| in the window.
MediaRequestChange(render_process_id2, render_frame_id2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
}
IN_PROC_BROWSER_TEST_F(MediaAccessWebAppsTest, RemoveApp) {
std::string app_id = CreateWebApp(GetUrl1());
// Launch |app_id| in a new tab.
web_app::LaunchWebAppBrowser(browser()->profile(), app_id);
web_app::NavigateToURLAndWait(browser(), GetUrl1());
// Request accessing the camera and the microphone for |app_id| in the new
// tab.
content::WebContents* web_content1 = GetWebContents();
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id));
// Launch |app_id| in a new window.
content::WebContents* web_content2 = OpenApplication(app_id);
Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
ASSERT_TRUE(app_browser);
ASSERT_NE(browser(), app_browser);
// Request accessing the camera and the microphone for |app_id| in the new
// window.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id));
UninstallWebApp(app_id);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
CreateWebApp(GetUrl1());
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id));
}
IN_PROC_BROWSER_TEST_F(MediaAccessWebAppsTest, TwoApps) {
std::string app_id1 = CreateWebApp(GetUrl1());
// Launch |app_id1| in a new tab.
web_app::LaunchWebAppBrowser(browser()->profile(), app_id1);
web_app::NavigateToURLAndWait(browser(), GetUrl1());
// Request accessing the camera and the microphone for |app_id1| in the new
// tab.
content::WebContents* web_content1 = GetWebContents();
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content1, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id1));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id1));
std::string app_id2 = CreateWebApp(GetUrl2());
// Launch |app_id2| in a new window.
content::WebContents* web_content2 = OpenApplication(app_id2);
Browser* app_browser = BrowserList::GetInstance()->GetLastActive();
ASSERT_TRUE(app_browser);
ASSERT_NE(browser(), app_browser);
// Request accessing the camera and the microphone for |app_id2| in the new
// window.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id2));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id2));
UninstallWebApp(app_id1);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id1));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id1));
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id2));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id2));
// Stop accessing the camera and the microphone for |app_id2|.
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
MediaRequestChangeForWebContent(
web_content2, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_CLOSING);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id2));
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id2));
// Navigate to Url1, and check |app_id1| is not accessing the camera or the
// microphone, because it has been removed.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl1()));
auto* web_content3 = GetWebContents();
MediaRequestChangeForWebContent(
web_content3, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content3, GetUrl1(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id1));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id1));
// Navigate to Url2, and check |app_id2| is accessing the camera and the
// microphone.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl2()));
auto* web_content4 = GetWebContents();
MediaRequestChangeForWebContent(
web_content4, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
MediaRequestChangeForWebContent(
web_content4, GetUrl2(),
blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE,
content::MEDIA_REQUEST_STATE_DONE);
EXPECT_TRUE(AccessingMicrophone(browser()->profile(), app_id2));
EXPECT_TRUE(AccessingCamera(browser()->profile(), app_id2));
EXPECT_FALSE(AccessingCamera(browser()->profile(), app_id1));
EXPECT_FALSE(AccessingMicrophone(browser()->profile(), app_id1));
}