#include "chrome/browser/web_applications/preinstalled_web_app_manager.h"
#include <string_view>
#include "base/auto_reset.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.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/intent_helper/preferred_apps_test_util.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/web_applications/test/ssl_test_utils.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/extension_status_utils.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/preinstalled_app_install_features.h"
#include "chrome/browser/web_applications/preinstalled_web_app_config_utils.h"
#include "chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h"
#include "chrome/browser/web_applications/test/os_integration_test_override_impl.h"
#include "chrome/browser/web_applications/test/test_file_utils.h"
#include "chrome/browser/web_applications/test/web_app_icon_test_utils.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/user_uninstalled_preinstalled_web_app_prefs.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/prefs/pref_service.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_update.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_launcher.h"
#include "content/public/test/url_loader_interceptor.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "net/ssl/ssl_info.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/device_data_manager_test_api.h"
#include "ui/events/devices/touchscreen_device.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/constants/chromeos_features.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/test/app_list_test_api.h"
#include "chrome/browser/ash/app_list/app_list_client_impl.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service_factory.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/web_applications/app_service/test/loopback_crosapi_app_service_proxy.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#endif
namespace web_app {
namespace {
constexpr char kBaseDataDir[] = …;
constexpr char kSimpleManifestStartUrl[] = …;
constexpr char kNoManifestTestPageStartUrl[] = …;
base::FilePath GetDataFilePath(const base::FilePath& relative_path,
bool* path_exists) { … }
#if BUILDFLAG(IS_CHROMEOS)
void ExpectInitialManifestFieldsFromBasicWebApp(WebAppIconManager& icon_manager,
const WebApp* web_app,
const GURL& expect_start_url,
const GURL& expect_scope) {
EXPECT_EQ(web_app->untranslated_name(), "Basic web app");
EXPECT_EQ(web_app->start_url().spec(), expect_start_url);
EXPECT_EQ(web_app->scope().spec(), expect_scope);
EXPECT_EQ(web_app->display_mode(), DisplayMode::kStandalone);
EXPECT_FALSE(web_app->theme_color().has_value());
EXPECT_FALSE(web_app->sync_proto().has_theme_color());
EXPECT_EQ("Basic web app", web_app->sync_proto().name());
EXPECT_EQ(expect_scope.spec(), web_app->sync_proto().scope());
ASSERT_EQ(2, web_app->sync_proto().icon_infos_size());
EXPECT_EQ(expect_start_url.Resolve("basic-48.png").spec(),
web_app->sync_proto().icon_infos(0).url());
EXPECT_EQ(48, web_app->sync_proto().icon_infos(0).size_in_px());
EXPECT_EQ(sync_pb::WebAppIconInfo_Purpose_ANY,
web_app->sync_proto().icon_infos(0).purpose());
EXPECT_EQ(expect_start_url.Resolve("basic-192.png").spec(),
web_app->sync_proto().icon_infos(1).url());
EXPECT_EQ(192, web_app->sync_proto().icon_infos(1).size_in_px());
EXPECT_EQ(sync_pb::WebAppIconInfo_Purpose_ANY,
web_app->sync_proto().icon_infos(1).purpose());
EXPECT_EQ(IconManagerReadAppIconPixel(icon_manager, web_app->app_id(),
192),
SK_ColorBLACK);
EXPECT_EQ(web_app->user_display_mode(), mojom::UserDisplayMode::kStandalone);
}
#endif
}
class PreinstalledWebAppManagerBrowserTestBase
: virtual public InProcessBrowserTest { … };
class PreinstalledWebAppManagerBrowserTest
: public PreinstalledWebAppManagerBrowserTestBase { … };
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
LaunchQueryParamsBasic) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
LaunchQueryParamsDuplicate) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
LaunchQueryParamsMultiple) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
LaunchQueryParamsComplex) { … }
class PreinstalledWebAppManagerExtensionBrowserTest
: public extensions::ExtensionBrowserTest,
public PreinstalledWebAppManagerBrowserTest { … };
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerExtensionBrowserTest,
UninstallAndReplace) { … }
#endif
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PreinstalledAppsPrefInstall) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PreinstalledAppsPrefNoinstall) { … }
const char kOnlyIfPreviouslyPreinstalled_PreviousConfig[] = …;
const char kOnlyIfPreviouslyPreinstalled_NextConfig[] = …;
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PRE_OnlyIfPreviouslyPreinstalled_AppPreserved) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OnlyIfPreviouslyPreinstalled_AppPreserved) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PRE_OnlyIfPreviouslyPreinstalled_NoAppPreinstalled) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OnlyIfPreviouslyPreinstalled_NoAppPreinstalled) { … }
const char kFeatureNameOrInstalledConfig[] = …;
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
GateOnFeatureNameOrInstalled_InstallWhenEnabled) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
GateOnFeatureNameOrInstalled_IgnoreWhenDisabled) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
Installed_DoNotUninstallWhenDisabled) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
DisableForPreinstalledAppsInConfig) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PreinstalledAppsUninstallOverride) { … }
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
IgnoreCorruptUserUninstalledPreinstalledWebAppPrefs) { … }
#if BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OfflineFallbackManifestSiteOffline) {
constexpr char kAppInstallUrl[] = "https://offline-site.com/install.html";
constexpr char kAppName[] = "Offline app name";
constexpr char kAppStartUrl[] = "https://offline-site.com/start.html";
constexpr char kAppScope[] = "https://offline-site.com/";
webapps::AppId app_id =
GenerateAppId(std::nullopt, GURL(kAppStartUrl));
EXPECT_FALSE(registrar().IsInstalled(app_id));
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"offline_manifest": {
"name": "$2",
"start_url": "$3",
"scope": "$4",
"display": "minimal-ui",
"theme_color_argb_hex": "AABBCCDD",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate, {kAppInstallUrl, kAppName, kAppStartUrl, kAppScope},
nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(GURL(kAppInstallUrl), app_config),
webapps::InstallResultCode::kSuccessOfflineFallbackInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppShortName(app_id), kAppName);
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), kAppStartUrl);
EXPECT_EQ(registrar().GetAppScope(app_id).spec(), kAppScope);
EXPECT_EQ(registrar().GetAppUserDisplayMode(app_id),
mojom::UserDisplayMode::kStandalone);
EXPECT_EQ(registrar().GetAppDisplayMode(app_id), DisplayMode::kMinimalUi);
EXPECT_EQ(registrar().GetAppThemeColor(app_id),
SkColorSetARGB(0xFF, 0xBB, 0xCC, 0xDD));
EXPECT_EQ(
IconManagerReadAppIconPixel(icon_manager(), app_id, 192),
SK_ColorBLUE);
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OfflineFallbackManifestSiteOnline) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL install_url = embedded_test_server()->GetURL("/web_apps/basic.html");
GURL offline_start_url = embedded_test_server()->GetURL(
"/web_apps/offline-only-start-url-that-does-not-exist.html");
GURL scope = embedded_test_server()->GetURL("/web_apps/");
webapps::AppId offline_app_id =
GenerateAppId(std::nullopt, offline_start_url);
EXPECT_FALSE(registrar().IsInstalled(offline_app_id));
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"offline_manifest": {
"name": "Offline only app name",
"start_url": "$2",
"scope": "$3",
"display": "minimal-ui",
"theme_color_argb_hex": "AABBCCDD",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate,
{install_url.spec(), offline_start_url.spec(), scope.spec()}, nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(install_url, app_config),
webapps::InstallResultCode::kSuccessNewInstall);
EXPECT_FALSE(registrar().IsInstalled(offline_app_id));
webapps::AppId app_id =
GenerateAppId(std::nullopt, install_url);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppShortName(app_id), "Basic web app");
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), install_url);
EXPECT_EQ(registrar().GetAppScope(app_id).spec(), scope);
EXPECT_EQ(registrar().GetAppUserDisplayMode(app_id),
mojom::UserDisplayMode::kStandalone);
EXPECT_EQ(registrar().GetAppDisplayMode(app_id), DisplayMode::kStandalone);
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OfflineOnlyManifestSiteOffline) {
constexpr char kAppInstallUrl[] = "https://offline-site.com/install.html";
constexpr char kAppName[] = "Offline app name";
constexpr char kAppStartUrl[] = "https://offline-site.com/start.html";
constexpr char kAppScope[] = "https://offline-site.com/";
webapps::AppId app_id =
GenerateAppId(std::nullopt, GURL(kAppStartUrl));
EXPECT_FALSE(registrar().IsInstalled(app_id));
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"only_use_offline_manifest": true,
"offline_manifest": {
"name": "$2",
"start_url": "$3",
"scope": "$4",
"display": "minimal-ui",
"theme_color_argb_hex": "AABBCCDD",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate, {kAppInstallUrl, kAppName, kAppStartUrl, kAppScope},
nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(GURL(kAppInstallUrl), app_config),
webapps::InstallResultCode::kSuccessOfflineOnlyInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppShortName(app_id), kAppName);
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), kAppStartUrl);
EXPECT_EQ(registrar().GetAppScope(app_id).spec(), kAppScope);
EXPECT_EQ(registrar().GetAppUserDisplayMode(app_id),
mojom::UserDisplayMode::kStandalone);
EXPECT_EQ(registrar().GetAppDisplayMode(app_id), DisplayMode::kMinimalUi);
EXPECT_EQ(registrar().GetAppThemeColor(app_id),
SkColorSetARGB(0xFF, 0xBB, 0xCC, 0xDD));
EXPECT_EQ(
IconManagerReadAppIconPixel(icon_manager(), app_id, 192),
SK_ColorBLUE);
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OfflineOnlyManifestSiteOnline) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL install_url = GetAppUrl();
const char kAppName[] = "Offline only app name";
GURL start_url = embedded_test_server()->GetURL(
"/web_apps/offline-only-start-url-that-does-not-exist.html");
GURL scope = embedded_test_server()->GetURL("/web_apps/");
webapps::AppId app_id =
GenerateAppId(std::nullopt, start_url);
EXPECT_FALSE(registrar().IsInstalled(app_id));
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"only_use_offline_manifest": true,
"offline_manifest": {
"name": "$2",
"start_url": "$3",
"scope": "$4",
"display": "minimal-ui",
"theme_color_argb_hex": "AABBCCDD",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate,
{install_url.spec(), kAppName, start_url.spec(), scope.spec()}, nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(install_url, app_config),
webapps::InstallResultCode::kSuccessOfflineOnlyInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
EXPECT_EQ(registrar().GetAppShortName(app_id), kAppName);
EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), start_url);
EXPECT_EQ(registrar().GetAppScope(app_id).spec(), scope);
EXPECT_EQ(registrar().GetAppUserDisplayMode(app_id),
mojom::UserDisplayMode::kStandalone);
EXPECT_EQ(registrar().GetAppDisplayMode(app_id), DisplayMode::kMinimalUi);
EXPECT_EQ(registrar().GetAppThemeColor(app_id),
SkColorSetARGB(0xFF, 0xBB, 0xCC, 0xDD));
EXPECT_EQ(
IconManagerReadAppIconPixel(icon_manager(), app_id, 192),
SK_ColorBLUE);
}
const char kOnlyForNewUsersInstallUrl[] = "https://example.org/";
const char kOnlyForNewUsersConfig[] = R"({
"app_url": "https://example.org/",
"launch_container": "window",
"user_type": ["unmanaged"],
"only_for_new_users": true,
"only_use_offline_manifest": true,
"offline_manifest": {
"name": "Test",
"start_url": "https://example.org/",
"scope": "https://example.org/",
"display": "standalone",
"icon_any_pngs": ["icon.png"]
}
})";
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PRE_OnlyForNewUsersWithNewUser) {
{
base::RunLoop run_loop;
WebAppPolicyManager& policy_manager =
WebAppProvider::GetForTest(profile())->policy_manager();
policy_manager.SetOnAppsSynchronizedCompletedCallbackForTesting(
run_loop.QuitClosure());
const char kWebAppPolicy[] = R"([{
"url": "https://policy-example.org/",
"default_launch_container": "window"
}])";
profile()->GetPrefs()->Set(prefs::kWebAppInstallForceList,
base::JSONReader::Read(kWebAppPolicy).value());
run_loop.Run();
}
EXPECT_EQ(SyncPreinstalledAppConfig(GURL(kOnlyForNewUsersInstallUrl),
kOnlyForNewUsersConfig),
webapps::InstallResultCode::kSuccessOfflineOnlyInstall);
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OnlyForNewUsersWithNewUser) {
EXPECT_EQ(SyncPreinstalledAppConfig(GURL(kOnlyForNewUsersInstallUrl),
kOnlyForNewUsersConfig),
webapps::InstallResultCode::kSuccessAlreadyInstalled);
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
PRE_OnlyForNewUsersWithOldUser) {
SyncEmptyConfigs();
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OnlyForNewUsersWithOldUser) {
EXPECT_EQ(SyncPreinstalledAppConfig(GURL(kOnlyForNewUsersInstallUrl),
kOnlyForNewUsersConfig),
std::nullopt);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest, OemInstalled) {
base::AutoReset<bool> bypass_offline_manifest_requirement =
PreinstalledWebAppManager::BypassOfflineManifestRequirementForTesting();
ASSERT_TRUE(embedded_test_server()->Start());
EXPECT_EQ(SyncPreinstalledAppConfig(GetAppUrl(),
base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"oem_installed": true,
"user_type": ["unmanaged"]
})",
{GetAppUrl().spec()}, nullptr)),
webapps::InstallResultCode::kSuccessNewInstall);
webapps::AppId app_id =
GenerateAppId(std::nullopt, GetAppUrl());
EXPECT_TRUE(registrar().WasInstalledByOem(app_id));
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
apps::InstallReason install_reason = apps::InstallReason::kUnknown;
proxy->AppRegistryCache().ForOneApp(app_id,
[&](const apps::AppUpdate& update) {
install_reason = update.InstallReason();
});
EXPECT_EQ(install_reason, apps::InstallReason::kOem);
}
#endif
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
namespace {
ui::TouchscreenDevice CreateTouchDevice(ui::InputDeviceType type,
bool stylus_support) {
ui::TouchscreenDevice touch_device = ui::TouchscreenDevice();
touch_device.type = type;
touch_device.has_stylus = stylus_support;
return touch_device;
}
}
#endif
IN_PROC_BROWSER_TEST_F(
PreinstalledWebAppManagerBrowserTest,
DisableIfTouchscreenWithStylusNotSupported_NoStylusSupport) {
base::AutoReset<bool> bypass_offline_manifest_requirement =
PreinstalledWebAppManager::BypassOfflineManifestRequirementForTesting();
ASSERT_TRUE(embedded_test_server()->Start());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto init_params = crosapi::mojom::BrowserInitParams::New();
init_params->device_properties = crosapi::mojom::DeviceProperties::New();
init_params->device_properties->has_stylus_enabled_touchscreen = false;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
#else
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(
{CreateTouchDevice(ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
false)});
#endif
const auto manifest = base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"disable_if_touchscreen_with_stylus_not_supported": true,
"user_type": ["unmanaged"]
})",
{GetAppUrl().spec()}, nullptr);
webapps::AppId app_id =
GenerateAppId(std::nullopt, GetAppUrl());
const auto& ignore_configs = manager().debug_info()->ignore_configs;
constexpr char kErrorMessage[] =
" ignore because the device does not have a built-in touchscreen with "
"stylus support.";
EXPECT_EQ(SyncPreinstalledAppConfig(GetAppUrl(), manifest), std::nullopt);
EXPECT_FALSE(registrar().IsInstalled(app_id));
EXPECT_EQ(ignore_configs.size(), 1u);
EXPECT_EQ(ignore_configs.back().second, GetAppUrl().spec() + kErrorMessage);
}
IN_PROC_BROWSER_TEST_F(
PreinstalledWebAppManagerBrowserTest,
DisableIfTouchscreenWithStylusNotSupported_HasStylusSupport) {
base::AutoReset<bool> bypass_offline_manifest_requirement =
PreinstalledWebAppManager::BypassOfflineManifestRequirementForTesting();
ASSERT_TRUE(embedded_test_server()->Start());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto init_params = crosapi::mojom::BrowserInitParams::New();
init_params->device_properties = crosapi::mojom::DeviceProperties::New();
init_params->device_properties->has_stylus_enabled_touchscreen = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
#else
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(
{CreateTouchDevice(ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
true)});
#endif
const auto manifest = base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"disable_if_touchscreen_with_stylus_not_supported": true,
"user_type": ["unmanaged"]
})",
{GetAppUrl().spec()}, nullptr);
webapps::AppId app_id =
GenerateAppId(std::nullopt, GetAppUrl());
EXPECT_EQ(SyncPreinstalledAppConfig(GetAppUrl(), manifest),
webapps::InstallResultCode::kSuccessNewInstall);
EXPECT_TRUE(registrar().IsInstalled(app_id));
}
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
DisableIfTouchscreenWithStylusStartupDelay) {
base::AutoReset<bool> bypass_offline_manifest_requirement =
PreinstalledWebAppManager::BypassOfflineManifestRequirementForTesting();
ASSERT_TRUE(embedded_test_server()->Start());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto init_params = crosapi::mojom::BrowserInitParams::New();
init_params->device_properties = crosapi::mojom::DeviceProperties::New();
init_params->device_properties->has_stylus_enabled_touchscreen = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
#endif
const auto manifest = base::ReplaceStringPlaceholders(
R"({
"app_url": "$1",
"launch_container": "window",
"disable_if_touchscreen_with_stylus_not_supported": true,
"user_type": ["unmanaged"]
})",
{GetAppUrl().spec()}, nullptr);
webapps::AppId app_id =
GenerateAppId(std::nullopt, GetAppUrl());
ui::DeviceDataManager::GetInstance()->ResetDeviceListsForTest();
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, base::BindLambdaForTesting([]() {
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
ui::DeviceDataManagerTestApi().SetTouchscreenDevices({CreateTouchDevice(
ui::InputDeviceType::INPUT_DEVICE_INTERNAL, true)});
#endif
ui::DeviceDataManagerTestApi().OnDeviceListsComplete();
}),
base::Milliseconds(500));
EXPECT_EQ(SyncPreinstalledAppConfig(GetAppUrl(), manifest),
webapps::InstallResultCode::kSuccessNewInstall);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
DISABLED_UninstallFromTwoItemAppListFolder) {
GURL preinstalled_app_start_url("https://example.org/");
GURL user_app_start_url("https://test.org/");
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile());
AppListClientImpl::GetInstance()->UpdateProfile();
ash::AppListTestApi app_list_test_api;
app_list::AppListSyncableService* app_list_syncable_service =
app_list::AppListSyncableServiceFactory::GetForProfile(profile());
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"only_use_offline_manifest": true,
"offline_manifest": {
"name": "Test default app",
"display": "standalone",
"start_url": "$1",
"scope": "$1",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate, {preinstalled_app_start_url.spec()}, nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(preinstalled_app_start_url, app_config),
webapps::InstallResultCode::kSuccessOfflineOnlyInstall);
webapps::AppId preinstalled_app_id =
GenerateAppId(std::nullopt, preinstalled_app_start_url);
auto install_info =
WebAppInstallInfo::CreateWithStartUrlForTesting(user_app_start_url);
install_info->title = u"Test user app";
webapps::AppId user_app_id =
web_app::test::InstallWebApp(profile(), std::move(install_info));
std::string folder_id = app_list_test_api.CreateFolderWithApps(
{preinstalled_app_id, user_app_id});
EXPECT_EQ(
app_list_syncable_service->GetSyncItem(preinstalled_app_id)->parent_id,
folder_id);
EXPECT_EQ(app_list_syncable_service->GetSyncItem(user_app_id)->parent_id,
folder_id);
proxy->UninstallSilently(preinstalled_app_id,
apps::UninstallSource::kUnknown);
EXPECT_FALSE(registrar().IsInstalled(preinstalled_app_id));
EXPECT_TRUE(registrar().IsInstalled(user_app_id));
EXPECT_FALSE(app_list_test_api.HasApp(preinstalled_app_id));
EXPECT_TRUE(app_list_test_api.HasApp(user_app_id));
EXPECT_EQ(
app_list_syncable_service->GetSyncItem(preinstalled_app_id)->parent_id,
"");
EXPECT_EQ(app_list_syncable_service->GetSyncItem(user_app_id)->parent_id, "");
}
#endif
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerBrowserTest,
OfflineOnlyManifest_SiteAlreadyInstalledFromSync) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL install_url = GetAppUrl();
GURL start_url = install_url;
GURL scope = embedded_test_server()->GetURL("/web_apps/");
const webapps::AppId app_id = InstallWebAppFromPage(browser(), install_url);
const WebApp* web_app = registrar().GetAppById(app_id);
ASSERT_TRUE(web_app);
EXPECT_TRUE(web_app->IsSynced());
EXPECT_FALSE(web_app->IsPreinstalledApp());
{
SCOPED_TRACE("Expect initial manifest fields from basic.html web app.");
ExpectInitialManifestFieldsFromBasicWebApp(icon_manager(), web_app,
start_url, scope);
}
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "tab",
"user_type": ["unmanaged"],
"only_use_offline_manifest": true,
"offline_manifest": {
"name": "$2",
"start_url": "$3",
"scope": "$4",
"display": "minimal-ui",
"theme_color_argb_hex": "AABBCCDD",
"icon_any_pngs": ["icon.png"]
}
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate,
{install_url.spec(), "Overwrite app name", start_url.spec(),
"https://overwrite.scope/"},
nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(install_url, app_config),
webapps::InstallResultCode::kSuccessOfflineOnlyInstall);
EXPECT_EQ(web_app, registrar().GetAppById(app_id));
EXPECT_TRUE(web_app->IsSynced());
EXPECT_TRUE(web_app->IsPreinstalledApp());
{
SCOPED_TRACE(
"Expect same manifest fields from basic.html web app, no overwrites.");
ExpectInitialManifestFieldsFromBasicWebApp(icon_manager(), web_app,
start_url, scope);
}
}
class PreinstalledWebAppManagerWithCloudGamingBrowserTest
: public PreinstalledWebAppManagerBrowserTest {
public:
PreinstalledWebAppManagerWithCloudGamingBrowserTest() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
auto params = crosapi::mojom::BrowserInitParams::New();
params->is_cloud_gaming_device = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(params));
#else
scoped_feature_list_.InitAndEnableFeature(
chromeos::features::kCloudGamingDevice);
#endif
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(PreinstalledWebAppManagerWithCloudGamingBrowserTest,
GateOnCloudGamingFeature) {
ASSERT_TRUE(embedded_test_server()->Start());
constexpr char kAppConfigTemplate[] =
R"({
"app_url": "$1",
"launch_container": "window",
"user_type": ["unmanaged"],
"feature_name": "$2"
})";
std::string app_config = base::ReplaceStringPlaceholders(
kAppConfigTemplate,
{GetAppUrl().spec(), chromeos::features::kCloudGamingDevice.name},
nullptr);
EXPECT_EQ(SyncPreinstalledAppConfig(GetAppUrl(), app_config),
webapps::InstallResultCode::kSuccessNewInstall);
}
#endif
class PreinstalledWebAppManagerPreferredAppForSupportedLinksBrowserTest
: public PreinstalledWebAppManagerBrowserTest,
public ::testing::WithParamInterface<
bool> { … };
INSTANTIATE_TEST_SUITE_P(…);
IN_PROC_BROWSER_TEST_P(
PreinstalledWebAppManagerPreferredAppForSupportedLinksBrowserTest,
MaybeSetPreferredAppForSupportedLinks) { … }
}