// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/app_service/lacros_web_apps_controller.h"
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.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/app_service/intent_util.h"
#include "chrome/browser/apps/app_service/launch_utils.h"
#include "chrome/browser/apps/browser_instance/browser_app_instance_tracker.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
#include "chrome/browser/notifications/notification_common.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/ui/web_applications/web_app_browsertest_base.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/os_integration/web_app_file_handler_manager.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_registry_update.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/crosapi/mojom/app_service.mojom.h"
#include "chromeos/crosapi/mojom/app_service_types.mojom-forward.h"
#include "chromeos/crosapi/mojom/app_service_types.mojom-shared.h"
#include "chromeos/crosapi/mojom/app_service_types.mojom.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/capability_access.h"
#include "components/services/app_service/public/cpp/icon_effects.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "components/services/app_service/public/cpp/intent_filter.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "components/services/app_service/public/cpp/permission.h"
#include "components/webapps/browser/install_result_code.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/media_stream_request.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/models/image_model.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "ui/message_center/public/cpp/notifier_id.h"
#include "url/gurl.h"
using apps::IconEffects;
namespace web_app {
namespace {
class MockAppPublisher : public crosapi::mojom::AppPublisher {
public:
explicit MockAppPublisher(Profile* profile) : profile_(profile) {
run_loop_ = std::make_unique<base::RunLoop>();
}
~MockAppPublisher() override = default;
void Wait() {
run_loop_->Run();
run_loop_ = std::make_unique<base::RunLoop>();
}
const std::vector<apps::AppPtr>& get_deltas() const { return app_deltas_; }
const std::vector<apps::CapabilityAccessPtr>& get_capability_access_deltas()
const {
return capability_access_deltas_;
}
void clear_deltas() { app_deltas_.clear(); }
private:
// crosapi::mojom::AppPublisher:
void OnApps(std::vector<apps::AppPtr> deltas) override {
std::vector<apps::AppPtr> app_deltas_to_publish;
for (auto& delta : deltas) {
if (delta) {
app_deltas_to_publish.push_back(delta->Clone());
app_deltas_.push_back(std::move(delta));
}
}
apps::AppServiceProxyFactory::GetForProfile(profile_)->OnApps(
std::move(app_deltas_to_publish), apps::AppType::kWeb,
/* should_notify_initialized */ false);
run_loop_->Quit();
}
void RegisterAppController(
mojo::PendingRemote<crosapi::mojom::AppController> controller) override {
NOTIMPLEMENTED();
}
void OnCapabilityAccesses(
std::vector<apps::CapabilityAccessPtr> deltas) override {
capability_access_deltas_.insert(capability_access_deltas_.end(),
std::make_move_iterator(deltas.begin()),
std::make_move_iterator(deltas.end()));
run_loop_->Quit();
}
std::vector<apps::AppPtr> app_deltas_;
std::vector<apps::CapabilityAccessPtr> capability_access_deltas_;
std::unique_ptr<base::RunLoop> run_loop_;
raw_ptr<Profile> profile_;
};
content::EvalJsResult ReadTextContent(content::WebContents* web_contents,
const char* id) {
const std::string script =
base::StringPrintf("document.getElementById('%s').textContent", id);
return content::EvalJs(web_contents, script);
}
// Returns whether there are file view filters among the given list of intent
// filters.
bool HasFileViewFilters(
const std::vector<apps::IntentFilterPtr>& intent_filters) {
for (const auto& intent_filter : intent_filters) {
bool has_action_view = false;
bool has_mime_type = false;
bool has_file_extension = false;
for (const auto& condition : intent_filter->conditions) {
switch (condition->condition_type) {
case apps::ConditionType::kAction:
if (condition->condition_values.size() == 1 &&
condition->condition_values.back()->value ==
apps_util::kIntentActionView) {
has_action_view = true;
}
break;
case apps::ConditionType::kFile:
for (const auto& condition_value : condition->condition_values) {
if (condition_value->match_type ==
apps::PatternMatchType::kMimeType) {
has_mime_type = true;
} else if (condition_value->match_type ==
apps::PatternMatchType::kFileExtension) {
has_file_extension = true;
}
}
break;
default:
// NOOP
break;
}
}
if (has_action_view && (has_mime_type || has_file_extension)) {
return true;
}
}
return false;
}
// Upcast to expose private AppController methods.
crosapi::mojom::AppController& AsAppController(
LacrosWebAppsController& lacros_web_apps_controller) {
return static_cast<crosapi::mojom::AppController&>(
lacros_web_apps_controller);
}
} // namespace
class LacrosWebAppsControllerBrowserTest : public WebAppBrowserTestBase {
public:
LacrosWebAppsControllerBrowserTest() = default;
~LacrosWebAppsControllerBrowserTest() override = default;
};
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, PublishApps) {
ASSERT_TRUE(embedded_test_server()->Start());
InstallWebAppFromManifest(
browser(), embedded_test_server()->GetURL("/web_apps/basic.html"));
InstallWebAppFromManifest(browser(), embedded_test_server()->GetURL(
"/web_share_target/charts.html"));
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
webapps::AppId app_id = InstallWebAppFromManifest(
browser(),
embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
mock_app_publisher.Wait();
// OnWebAppInstalled(), OnWebAppInstalledWithOsHooks() and
// OnWebAppLastLaunchTimeChanged() lead to updates.
const auto& app_deltas = mock_app_publisher.get_deltas();
EXPECT_EQ(app_deltas.size(), 5U);
EXPECT_EQ(app_deltas.back()->app_id, app_id);
bool found_ready_with_icon = false;
// The order of those three updates is not important
for (std::vector<apps::AppPtr>::size_type i = 2; i < app_deltas.size(); i++) {
EXPECT_EQ(app_deltas[i]->app_id, app_id);
if (app_deltas[i]->readiness == apps::Readiness::kReady) {
EXPECT_EQ(app_deltas[i]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
found_ready_with_icon = true;
}
}
EXPECT_TRUE(found_ready_with_icon);
{
test::UninstallWebApp(profile(), app_id);
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->readiness,
apps::Readiness::kUninstalledByUser);
}
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, LaunchTime) {
ASSERT_TRUE(embedded_test_server()->Start());
webapps::AppId app_id = InstallWebAppFromManifest(
browser(), embedded_test_server()->GetURL("/web_apps/basic.html"));
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
ASSERT_TRUE(
mock_app_publisher.get_deltas().back()->last_launch_time.has_value());
const base::Time last_launch_time =
*mock_app_publisher.get_deltas().back()->last_launch_time;
LaunchWebAppBrowser(app_id);
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
ASSERT_TRUE(
mock_app_publisher.get_deltas().back()->last_launch_time.has_value());
EXPECT_GT(*mock_app_publisher.get_deltas().back()->last_launch_time,
last_launch_time);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, ManifestUpdate) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url =
embedded_test_server()->GetURL("app.site.com", "/simple.html");
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
webapps::AppId app_id;
{
const std::u16string original_description = u"Original Web App";
auto web_app_info =
WebAppInstallInfo::CreateWithStartUrlForTesting(app_url);
web_app_info->scope = app_url;
web_app_info->title = original_description;
web_app_info->description = original_description;
app_id = InstallWebApp(std::move(web_app_info));
mock_app_publisher.Wait();
EXPECT_EQ(*mock_app_publisher.get_deltas().back()->description,
base::UTF16ToUTF8(original_description));
}
{
const std::u16string updated_description = u"Updated Web App";
auto web_app_info =
WebAppInstallInfo::CreateWithStartUrlForTesting(app_url);
web_app_info->scope = app_url;
web_app_info->title = updated_description;
web_app_info->description = updated_description;
base::RunLoop run_loop;
provider().install_finalizer().FinalizeUpdate(
*web_app_info,
base::BindLambdaForTesting([&run_loop](
const webapps::AppId& app_id,
webapps::InstallResultCode code) {
EXPECT_EQ(code, webapps::InstallResultCode::kSuccessAlreadyInstalled);
run_loop.Quit();
}));
run_loop.Run();
mock_app_publisher.Wait();
EXPECT_EQ(*mock_app_publisher.get_deltas().back()->description,
base::UTF16ToUTF8(updated_description));
}
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest,
LocallyInstalledState) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url =
embedded_test_server()->GetURL("app.site.com", "/simple.html");
webapps::AppId app_id;
{
const std::u16string description = u"Web App";
auto web_app_info =
WebAppInstallInfo::CreateWithStartUrlForTesting(app_url);
web_app_info->scope = app_url;
web_app_info->title = description;
web_app_info->description = description;
app_id = InstallWebApp(std::move(web_app_info));
provider().sync_bridge_unsafe().SetAppNotLocallyInstalledForTesting(app_id);
}
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
static_cast<IconEffects>(IconEffects::kRoundCorners |
IconEffects::kBlocked |
IconEffects::kCrOsStandardMask));
base::test::TestFuture<void> future;
provider().scheduler().InstallAppLocally(app_id, future.GetCallback());
ASSERT_TRUE(future.Wait());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardMask);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, PolicyIds) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
const GURL install_url =
embedded_test_server()->GetURL("/web_apps/get_manifest.html?basic.json");
webapps::AppId app_id = InstallWebAppFromPage(browser(), install_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().back()->publisher_id,
app_url.spec());
EXPECT_TRUE(mock_app_publisher.get_deltas().back()->policy_ids.empty());
// Writing to the external prefs to set policy to pin the app.
web_app::test::AddInstallUrlData(
browser()->profile()->GetPrefs(), &provider().sync_bridge_unsafe(),
app_id, install_url, ExternalInstallSource::kExternalPolicy);
// Add a mock secondary install url to verify that all values are propagated
// to policy_ids correctly.
const GURL secondary_install_url{"http://install.url/manifest.json"};
web_app::test::AddInstallUrlData(
browser()->profile()->GetPrefs(), &provider().sync_bridge_unsafe(),
app_id, secondary_install_url, ExternalInstallSource::kExternalPolicy);
provider().install_manager().NotifyWebAppInstalledWithOsHooks(app_id);
mock_app_publisher.Wait();
EXPECT_THAT(mock_app_publisher.get_deltas().back()->policy_ids,
testing::UnorderedElementsAre(install_url.spec(),
secondary_install_url.spec()));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, ContentSettings) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
// Install an additional app from a different host.
{
auto web_app_info = WebAppInstallInfo::CreateWithStartUrlForTesting(
GURL("https://example.com:8080/"));
web_app_info->scope = web_app_info->start_url();
web_app_info->title = u"Unrelated Web App";
InstallWebApp(std::move(web_app_info));
}
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
HostContentSettingsMap* content_settings_map =
HostContentSettingsMapFactory::GetForProfile(profile());
content_settings_map->SetContentSettingDefaultScope(
app_url, app_url, ContentSettingsType::MEDIASTREAM_CAMERA,
CONTENT_SETTING_ALLOW);
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 3U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_type,
apps::AppType::kWeb);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
const std::vector<apps::PermissionPtr>& permissions =
mock_app_publisher.get_deltas().back()->permissions;
auto camera_permission =
base::ranges::find(permissions, apps::PermissionType::kCamera,
&apps::Permission::permission_type);
ASSERT_TRUE(camera_permission != permissions.end());
EXPECT_TRUE(
absl::holds_alternative<apps::TriState>((*camera_permission)->value));
EXPECT_EQ(absl::get<apps::TriState>((*camera_permission)->value),
apps::TriState::kAllow);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, MediaRequest) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
Browser* browser = LaunchWebAppBrowserAndWait(app_id);
content::WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController& lacros_web_apps_controller =
*apps::AppServiceProxyFactory::GetForProfile(profile())
->LacrosWebAppsControllerForTesting();
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
// Register and start a fake device streaming microphone audio.
blink::mojom::StreamDevices fake_devices;
blink::MediaStreamDevice device(
blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE, "fake_device",
"fake_device");
fake_devices.audio_device = device;
std::unique_ptr<content::MediaStreamUI> ui =
MediaCaptureDevicesDispatcher::GetInstance()
->GetMediaStreamCaptureIndicator()
->RegisterMediaStream(web_contents, fake_devices);
ui->OnStarted(base::RepeatingClosure(),
content::MediaStreamUI::SourceCallback(),
/*label=*/std::string(), /*screen_capture_ids=*/{},
content::MediaStreamUI::StateChangeCallback());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().size(), 1U);
EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->app_id,
app_id);
EXPECT_FALSE(mock_app_publisher.get_capability_access_deltas()
.back()
->camera.has_value());
EXPECT_TRUE(mock_app_publisher.get_capability_access_deltas()
.back()
->microphone.value_or(false));
browser->tab_strip_model()->CloseAllTabs();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().size(), 2U);
EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->app_id,
app_id);
EXPECT_FALSE(mock_app_publisher.get_capability_access_deltas()
.back()
->camera.has_value());
EXPECT_FALSE(mock_app_publisher.get_capability_access_deltas()
.back()
->microphone.value_or(true));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, Launch) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
content::TestNavigationObserver navigation_observer(app_url);
navigation_observer.StartWatchingNewWebContents();
auto launch_params = crosapi::mojom::LaunchParams::New();
launch_params->app_id = app_id;
launch_params->launch_source = apps::LaunchSource::kFromTest;
launch_params->container =
crosapi::mojom::LaunchContainer::kLaunchContainerWindow;
launch_params->disposition =
crosapi::mojom::WindowOpenDisposition::kNewWindow;
AsAppController(lacros_web_apps_controller)
.Launch(std::move(launch_params), base::DoNothing());
navigation_observer.Wait();
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, LaunchWithFiles) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url =
embedded_test_server()->GetURL("/web_apps/file_handler_index.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
ASSERT_FALSE(app_id.empty());
EXPECT_EQ(provider().registrar_unsafe().GetAppStartUrl(app_id), app_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
const GURL launch_url =
embedded_test_server()->GetURL("/web_apps/file_handler_action.html");
content::TestNavigationObserver navigation_observer(launch_url);
navigation_observer.StartWatchingNewWebContents();
auto launch_params = crosapi::mojom::LaunchParams::New();
launch_params->app_id = app_id;
launch_params->container =
crosapi::mojom::LaunchContainer::kLaunchContainerWindow;
launch_params->disposition =
crosapi::mojom::WindowOpenDisposition::kNewWindow;
launch_params->launch_source = apps::LaunchSource::kFromTest;
launch_params->intent = crosapi::mojom::Intent::New();
launch_params->intent->action = apps_util::kIntentActionView;
launch_params->intent->activity_name = launch_url.spec();
auto intent_file = crosapi::mojom::IntentFile::New();
intent_file->file_path = base::FilePath("/path/not/actually/used/file.txt");
std::vector<crosapi::mojom::IntentFilePtr> files;
files.push_back(std::move(intent_file));
launch_params->intent->files = std::move(files);
// Skip past the permission dialog.
{
ScopedRegistryUpdate update = WebAppProvider::GetForTest(profile())
->sync_bridge_unsafe()
.BeginUpdate();
update->UpdateApp(app_id)->SetFileHandlerApprovalState(
ApiApprovalState::kAllowed);
}
AsAppController(lacros_web_apps_controller)
.Launch(std::move(launch_params), base::DoNothing());
navigation_observer.Wait();
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, PauseUnpause) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
MockAppPublisher mock_app_publisher(profile());
apps::AppServiceProxyLacros& app_service =
*apps::AppServiceProxyFactory::GetForProfile(profile());
LacrosWebAppsController& lacros_web_apps_controller =
*app_service.LacrosWebAppsControllerForTesting();
app_service.SetBrowserAppInstanceTrackerForTesting(
std::make_unique<apps::BrowserAppInstanceTracker>(
profile(), app_service.AppRegistryCache()));
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
const webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
LaunchWebAppBrowserAndWait(app_id);
mock_app_publisher.Wait();
// Ignore deltas from installation etc.
mock_app_publisher.clear_deltas();
AsAppController(lacros_web_apps_controller).PauseApp(app_id);
mock_app_publisher.Wait();
ASSERT_EQ(mock_app_publisher.get_deltas().size(), 2U);
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->app_type, apps::AppType::kWeb);
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon |
IconEffects::kPaused);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->app_type, apps::AppType::kWeb);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->app_id, app_id);
EXPECT_TRUE(mock_app_publisher.get_deltas()[1]->paused.value_or(false));
AsAppController(lacros_web_apps_controller).UnpauseApp(app_id);
mock_app_publisher.Wait();
ASSERT_EQ(mock_app_publisher.get_deltas().size(), 4U);
EXPECT_EQ(mock_app_publisher.get_deltas()[2]->app_type, apps::AppType::kWeb);
EXPECT_EQ(mock_app_publisher.get_deltas()[2]->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas()[2]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
EXPECT_EQ(mock_app_publisher.get_deltas()[3]->app_type, apps::AppType::kWeb);
EXPECT_EQ(mock_app_publisher.get_deltas()[3]->app_id, app_id);
EXPECT_FALSE(mock_app_publisher.get_deltas()[3]->paused.value_or(true));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, StopApp) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
MockAppPublisher mock_app_publisher(profile());
apps::AppServiceProxyLacros& app_service =
*apps::AppServiceProxyFactory::GetForProfile(profile());
LacrosWebAppsController& lacros_web_apps_controller =
*app_service.LacrosWebAppsControllerForTesting();
app_service.SetBrowserAppInstanceTrackerForTesting(
std::make_unique<apps::BrowserAppInstanceTracker>(
profile(), app_service.AppRegistryCache()));
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
const webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
Browser* app_browser = LaunchWebAppBrowserAndWait(app_id);
AsAppController(lacros_web_apps_controller).StopApp(app_id);
ui_test_utils::WaitForBrowserToClose(app_browser);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, GetMenuModel) {
auto CheckMenuItem = [](const crosapi::mojom::MenuItem& menu_item,
const std::string& label,
std::optional<SkColor> color) {
EXPECT_EQ(menu_item.label, label);
if (color.has_value()) {
EXPECT_FALSE(menu_item.image.isNull());
EXPECT_EQ(menu_item.image.bitmap()->getColor(15, 15), color);
} else {
EXPECT_TRUE(menu_item.image.isNull());
}
};
const GURL app_url =
https_server()->GetURL("/web_app_shortcuts/shortcuts.html");
const webapps::AppId app_id = InstallWebAppFromPage(browser(), app_url);
crosapi::mojom::AppController& lacros_web_apps_controller =
*apps::AppServiceProxyFactory::GetForProfile(profile())
->LacrosWebAppsControllerForTesting();
crosapi::mojom::MenuItemsPtr menu_items;
{
base::RunLoop run_loop;
lacros_web_apps_controller.GetMenuModel(
app_id,
base::BindLambdaForTesting(
[&run_loop, &menu_items](crosapi::mojom::MenuItemsPtr items) {
menu_items = std::move(items);
run_loop.Quit();
}));
run_loop.Run();
}
ASSERT_TRUE(menu_items);
ASSERT_EQ(6U, menu_items->items.size());
CheckMenuItem(*menu_items->items[0], "One", SK_ColorGREEN);
CheckMenuItem(*menu_items->items[1], "Two", SK_ColorBLUE);
CheckMenuItem(*menu_items->items[2], "Three", SK_ColorYELLOW);
CheckMenuItem(*menu_items->items[3], "Four", SK_ColorCYAN);
CheckMenuItem(*menu_items->items[4], "Five", SK_ColorMAGENTA);
CheckMenuItem(*menu_items->items[5], "Six", std::nullopt);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest,
ExecuteContextMenuCommand) {
const GURL app_url =
https_server()->GetURL("/web_app_shortcuts/shortcuts.html");
const webapps::AppId app_id = InstallWebAppFromPage(browser(), app_url);
LacrosWebAppsController& lacros_web_apps_controller =
*apps::AppServiceProxyFactory::GetForProfile(profile())
->LacrosWebAppsControllerForTesting();
crosapi::mojom::MenuItemsPtr menu_items;
base::test::TestFuture<crosapi::mojom::MenuItemsPtr> menu_items_future;
AsAppController(lacros_web_apps_controller)
.GetMenuModel(app_id, menu_items_future.GetCallback());
menu_items = menu_items_future.Take();
ASSERT_TRUE(menu_items);
ASSERT_EQ(6U, menu_items->items.size());
auto id = *menu_items->items[5]->id;
ui_test_utils::BrowserChangeObserver new_app_browser_observer(
nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
base::test::TestFuture<::crosapi::mojom::LaunchResultPtr>
launch_result_future;
AsAppController(lacros_web_apps_controller)
.ExecuteContextMenuCommand(app_id, id,
launch_result_future.GetCallback());
// TODO: handle return value.
std::ignore = launch_result_future.Wait();
ui_test_utils::WaitForBrowserSetLastActive(new_app_browser_observer.Wait());
EXPECT_EQ(BrowserList::GetInstance()
->GetLastActive()
->tab_strip_model()
->GetActiveWebContents()
->GetVisibleURL(),
https_server()->GetURL("/web_app_shortcuts/shortcuts.html#six"));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, OpenNativeSettings) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
AsAppController(lacros_web_apps_controller).OpenNativeSettings(app_id);
content::WebContents* const web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
std::string expected_url = base::StrCat(
{chrome::kChromeUISettingsURL, chrome::kContentSettingsSubPage});
EXPECT_TRUE(base::StartsWith(web_contents->GetVisibleURL().spec(),
expected_url, base::CompareCase::SENSITIVE));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, WindowMode) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->window_mode,
apps::WindowMode::kWindow);
AsAppController(lacros_web_apps_controller)
.SetWindowMode(app_id, apps::WindowMode::kBrowser);
mock_app_publisher.Wait();
EXPECT_GE(mock_app_publisher.get_deltas().size(), 2U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->window_mode,
apps::WindowMode::kBrowser);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, Notification) {
ASSERT_TRUE(embedded_test_server()->Start());
const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
webapps::AppId app_id = InstallWebAppFromManifest(browser(), app_url);
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_FALSE(
mock_app_publisher.get_deltas().back()->has_badge.value_or(true));
const GURL origin = app_url.DeprecatedGetOriginAsURL();
const std::string notification_id = "notification-id";
auto notification = std::make_unique<message_center::Notification>(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
std::u16string(), std::u16string(), ui::ImageModel(),
base::UTF8ToUTF16(origin.host()), origin,
message_center::NotifierId(origin),
message_center::RichNotificationData(), nullptr);
auto metadata = std::make_unique<PersistentNotificationMetadata>();
metadata->service_worker_scope = app_url.GetWithoutFilename();
NotificationDisplayService::GetForProfile(profile())->Display(
NotificationHandler::Type::WEB_PERSISTENT, *notification,
std::move(metadata));
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
EXPECT_TRUE(
mock_app_publisher.get_deltas().back()->has_badge.value_or(false));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, DisabledState) {
ASSERT_TRUE(embedded_test_server()->Start());
WebAppSyncBridge& web_app_sync_bridge = provider().sync_bridge_unsafe();
const webapps::AppId app_id = InstallWebAppFromManifest(
browser(), embedded_test_server()->GetURL("/web_apps/basic.html"));
webapps::AppId app2_id;
{
const std::u16string description = u"Uninstalled Web App";
GURL start_url =
embedded_test_server()->GetURL("app.site.com", "/simple.html");
auto web_app_info =
WebAppInstallInfo::CreateWithStartUrlForTesting(start_url);
web_app_info->scope = web_app_info->start_url().GetWithoutFilename();
web_app_info->title = description;
web_app_info->description = description;
app2_id = InstallWebApp(std::move(web_app_info));
web_app_sync_bridge.SetAppNotLocallyInstalledForTesting(app2_id);
}
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
if (mock_app_publisher.get_deltas()[0]->app_id == app_id) {
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->app_id, app2_id);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardMask |
IconEffects::kBlocked);
} else {
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->app_id, app2_id);
EXPECT_EQ(mock_app_publisher.get_deltas()[0]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardMask |
IconEffects::kBlocked);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas()[1]->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
}
provider().scheduler().SetAppIsDisabled(app_id, true, base::DoNothing());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 3U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon |
IconEffects::kBlocked);
provider().scheduler().SetAppIsDisabled(app2_id, true, base::DoNothing());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 4U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app2_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardMask |
IconEffects::kBlocked);
provider().scheduler().SetAppIsDisabled(app_id, false, base::DoNothing());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 5U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
provider().scheduler().SetAppIsDisabled(app2_id, false, base::DoNothing());
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 6U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app2_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardMask |
IconEffects::kBlocked);
provider().install_manager().NotifyWebAppManifestUpdated(app_id);
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 7U);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->app_id, app_id);
EXPECT_EQ(mock_app_publisher.get_deltas().back()->icon_key->icon_effects,
IconEffects::kRoundCorners | IconEffects::kCrOsStandardIcon);
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, GetLink) {
ASSERT_TRUE(embedded_test_server()->Start());
const webapps::AppId app_id = InstallWebAppFromManifest(
browser(),
embedded_test_server()->GetURL("/web_share_target/gatherer.html"));
const GURL share_target_url =
embedded_test_server()->GetURL("/web_share_target/share.html");
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_FALSE(mock_app_publisher.get_deltas().back()->intent_filters.empty());
const std::string shared_title = "My News";
const std::string shared_link = "http://example.com/news";
const GURL expected_url(share_target_url.spec() +
"?headline=My+News&link=http://example.com/news");
ui_test_utils::AllBrowserTabAddedWaiter waiter;
{
auto launch_params = apps::CreateCrosapiLaunchParamsWithEventFlags(
apps::AppServiceProxyFactory::GetForProfile(profile()), app_id,
/*event_flags=*/0, apps::LaunchSource::kFromSharesheet,
display::kInvalidDisplayId);
launch_params->container =
crosapi::mojom::LaunchContainer::kLaunchContainerWindow;
launch_params->disposition =
crosapi::mojom::WindowOpenDisposition::kNewWindow;
launch_params->intent = apps_util::ConvertAppServiceToCrosapiIntent(
apps_util::MakeShareIntent(shared_link, shared_title), profile());
AsAppController(lacros_web_apps_controller)
.Launch(std::move(launch_params), base::DoNothing());
}
content::WebContents* const web_contents = waiter.Wait();
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
EXPECT_EQ("GET", ReadTextContent(web_contents, "method"));
EXPECT_EQ(expected_url.spec(), ReadTextContent(web_contents, "url"));
EXPECT_EQ(shared_title, ReadTextContent(web_contents, "headline"));
// Gatherer web app's service worker detects omitted value.
EXPECT_EQ("N/A", ReadTextContent(web_contents, "author"));
EXPECT_EQ(shared_link, ReadTextContent(web_contents, "link"));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, ShareImage) {
ASSERT_TRUE(embedded_test_server()->Start());
const webapps::AppId app_id = InstallWebAppFromManifest(
browser(),
embedded_test_server()->GetURL("/web_share_target/multimedia.html"));
const std::string kData(12, '*');
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_FALSE(mock_app_publisher.get_deltas().back()->intent_filters.empty());
base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath image_file =
temp_dir.GetPath().Append(FILE_PATH_LITERAL("sample.webp"));
ASSERT_TRUE(base::WriteFile(image_file, kData));
ui_test_utils::AllBrowserTabAddedWaiter waiter;
{
crosapi::mojom::IntentPtr crosapi_intent = crosapi::mojom::Intent::New();
crosapi_intent->action = apps_util::kIntentActionSend;
crosapi_intent->mime_type = "image/webp";
std::vector<crosapi::mojom::IntentFilePtr> crosapi_files;
auto crosapi_file = crosapi::mojom::IntentFile::New();
crosapi_file->file_path = image_file;
crosapi_files.push_back(std::move(crosapi_file));
crosapi_intent->files = std::move(crosapi_files);
auto launch_params = apps::CreateCrosapiLaunchParamsWithEventFlags(
apps::AppServiceProxyFactory::GetForProfile(profile()), app_id,
/*event_flags=*/0, apps::LaunchSource::kFromSharesheet,
display::kInvalidDisplayId);
launch_params->intent = std::move(crosapi_intent);
launch_params->container =
crosapi::mojom::LaunchContainer::kLaunchContainerWindow;
launch_params->disposition =
crosapi::mojom::WindowOpenDisposition::kNewWindow;
AsAppController(lacros_web_apps_controller)
.Launch(std::move(launch_params), base::DoNothing());
}
content::WebContents* const web_contents = waiter.Wait();
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
EXPECT_EQ("POST", ReadTextContent(web_contents, "method"));
EXPECT_EQ(kData, ReadTextContent(web_contents, "image"));
EXPECT_EQ("sample.webp", ReadTextContent(web_contents, "image_filename"));
}
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest, ShareMultimedia) {
ASSERT_TRUE(embedded_test_server()->Start());
const webapps::AppId app_id = InstallWebAppFromManifest(
browser(),
embedded_test_server()->GetURL("/web_share_target/multimedia.html"));
const std::string kAudioContent(345, '*');
const std::string kVideoContent(67890, '*');
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_FALSE(mock_app_publisher.get_deltas().back()->intent_filters.empty());
base::ScopedAllowBlockingForTesting allow_blocking;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath audio_file =
temp_dir.GetPath().Append(FILE_PATH_LITERAL("sam.ple.mp3"));
ASSERT_TRUE(base::WriteFile(audio_file, kAudioContent));
base::FilePath video_file =
temp_dir.GetPath().Append(FILE_PATH_LITERAL("_sample.mp4"));
ASSERT_TRUE(base::WriteFile(video_file, kVideoContent));
ui_test_utils::AllBrowserTabAddedWaiter waiter;
{
crosapi::mojom::IntentPtr crosapi_intent = crosapi::mojom::Intent::New();
crosapi_intent->action = apps_util::kIntentActionSendMultiple;
crosapi_intent->mime_type = "*/*";
std::vector<crosapi::mojom::IntentFilePtr> crosapi_files;
{
auto crosapi_file = crosapi::mojom::IntentFile::New();
crosapi_file->file_path = audio_file;
crosapi_file->mime_type = "audio/mpeg";
crosapi_files.push_back(std::move(crosapi_file));
}
{
auto crosapi_file = crosapi::mojom::IntentFile::New();
crosapi_file->file_path = video_file;
crosapi_file->mime_type = "video/mp4";
crosapi_files.push_back(std::move(crosapi_file));
}
crosapi_intent->files = std::move(crosapi_files);
auto launch_params = apps::CreateCrosapiLaunchParamsWithEventFlags(
apps::AppServiceProxyFactory::GetForProfile(profile()), app_id,
/*event_flags=*/0, apps::LaunchSource::kFromSharesheet,
display::kInvalidDisplayId);
launch_params->intent = std::move(crosapi_intent);
launch_params->container =
crosapi::mojom::LaunchContainer::kLaunchContainerWindow;
launch_params->disposition =
crosapi::mojom::WindowOpenDisposition::kNewWindow;
AsAppController(lacros_web_apps_controller)
.Launch(std::move(launch_params), base::DoNothing());
}
content::WebContents* const web_contents = waiter.Wait();
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
EXPECT_EQ(kAudioContent, ReadTextContent(web_contents, "audio"));
EXPECT_EQ(kVideoContent, ReadTextContent(web_contents, "video"));
EXPECT_EQ("sam.ple.mp3", ReadTextContent(web_contents, "audio_filename"));
EXPECT_EQ("_sample.mp4", ReadTextContent(web_contents, "video_filename"));
}
// Regression test for crbug.com/1266642
IN_PROC_BROWSER_TEST_F(LacrosWebAppsControllerBrowserTest,
PublishOnlyEnabledFileHandlers) {
ASSERT_TRUE(embedded_test_server()->Start());
auto app_id = InstallWebAppFromManifest(
browser(),
embedded_test_server()->GetURL("/web_app_file_handling/basic_app.html"));
ASSERT_FALSE(app_id.empty());
MockAppPublisher mock_app_publisher(profile());
LacrosWebAppsController lacros_web_apps_controller(profile());
lacros_web_apps_controller.SetPublisherForTesting(&mock_app_publisher);
lacros_web_apps_controller.Init();
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
EXPECT_TRUE(HasFileViewFilters(
mock_app_publisher.get_deltas().back()->intent_filters));
EXPECT_EQ(
ApiApprovalState::kRequiresPrompt,
provider().registrar_unsafe().GetAppFileHandlerApprovalState(app_id));
provider().sync_bridge_unsafe().SetAppFileHandlerApprovalState(
app_id, ApiApprovalState::kDisallowed);
mock_app_publisher.Wait();
EXPECT_EQ(mock_app_publisher.get_deltas().size(), 2U);
EXPECT_FALSE(HasFileViewFilters(
mock_app_publisher.get_deltas().back()->intent_filters));
}
} // namespace web_app