#include "chrome/browser/web_applications/app_service/web_apps.h"
#include <utility>
#include "base/feature_list.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/trace_event.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/profiles/profile.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_id_constants.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_utils.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/services/app_service/public/cpp/icon_effects.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/app_menu_constants.h"
#include "ash/webui/projector_app/public/cpp/projector_app_constants.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/apps/almanac_api_client/device_info_manager.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/menu_item_constants.h"
#include "chrome/browser/apps/app_service/menu_util.h"
#include "chrome/browser/apps/app_service/promise_apps/promise_app_web_apps_utils.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ash/guest_os/guest_os_terminal.h"
#include "chrome/browser/ash/mall/mall_url.h"
#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/grit/generated_resources.h"
#include "components/services/app_service/public/cpp/instance_registry.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#endif
IconEffects;
namespace web_app {
WebApps::WebApps(apps::AppServiceProxy* proxy)
: … { … }
WebApps::~WebApps() = default;
void WebApps::Shutdown() { … }
const WebApp* WebApps::GetWebApp(const webapps::AppId& app_id) const { … }
void WebApps::Initialize() { … }
void WebApps::LoadIcon(const std::string& app_id,
const apps::IconKey& icon_key,
apps::IconType icon_type,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
apps::LoadIconCallback callback) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void WebApps::GetCompressedIconData(const std::string& app_id,
int32_t size_in_dip,
ui::ResourceScaleFactor scale_factor,
apps::LoadIconCallback callback) {
publisher_helper().GetCompressedIconData(app_id, size_in_dip, scale_factor,
std::move(callback));
}
#endif
void WebApps::Launch(const std::string& app_id,
int32_t event_flags,
apps::LaunchSource launch_source,
apps::WindowInfoPtr window_info) { … }
void WebApps::LaunchAppWithFiles(const std::string& app_id,
int32_t event_flags,
apps::LaunchSource launch_source,
std::vector<base::FilePath> file_paths) { … }
void WebApps::LaunchAppWithIntent(const std::string& app_id,
int32_t event_flags,
apps::IntentPtr intent,
apps::LaunchSource launch_source,
apps::WindowInfoPtr window_info,
apps::LaunchCallback callback) { … }
void WebApps::LaunchAppWithParams(apps::AppLaunchParams&& params,
apps::LaunchCallback callback) { … }
void WebApps::LaunchShortcut(const std::string& app_id,
const std::string& shortcut_id,
int64_t display_id) { … }
void WebApps::SetPermission(const std::string& app_id,
apps::PermissionPtr permission) { … }
void WebApps::Uninstall(const std::string& app_id,
apps::UninstallSource uninstall_source,
bool clear_site_data,
bool report_abuse) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void WebApps::GetMenuModel(const std::string& app_id,
apps::MenuType menu_type,
int64_t display_id,
base::OnceCallback<void(apps::MenuItems)> callback) {
const auto* web_app = GetWebApp(app_id);
if (!web_app) {
std::move(callback).Run(apps::MenuItems());
return;
}
bool can_close = true;
apps::AppServiceProxyFactory::GetForProfile(profile())
->AppRegistryCache()
.ForOneApp(app_id, [&can_close](const apps::AppUpdate& update) {
can_close = update.AllowClose().value_or(true);
});
apps::MenuItems menu_items;
auto* swa_manager = ash::SystemWebAppManager::Get(profile());
if (swa_manager && swa_manager->IsSystemWebApp(web_app->app_id())) {
DCHECK(web_app->client_data().system_web_app_data.has_value());
ash::SystemWebAppType swa_type =
web_app->client_data().system_web_app_data->system_app_type;
auto* system_app = swa_manager->GetSystemApp(swa_type);
if (system_app && system_app->ShouldShowNewWindowMenuOption()) {
apps::AddCommandItem(ash::LAUNCH_NEW,
IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW, menu_items);
}
} else if (can_close) {
if (web_app->isolation_data().has_value()) {
apps::AddCommandItem(ash::LAUNCH_NEW,
IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW, menu_items);
} else {
apps::CreateOpenNewSubmenu(
publisher_helper().GetWindowMode(app_id) == apps::WindowMode::kBrowser
? IDS_APP_LIST_CONTEXT_MENU_NEW_TAB
: IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW,
menu_items);
}
}
if (app_id == guest_os::kTerminalSystemAppId) {
guest_os::AddTerminalMenuItems(profile_, menu_items);
}
if (ShouldAddCloseItem(app_id, menu_type, profile_)) {
apps::AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE,
menu_items);
}
if (web_app->CanUserUninstallWebApp()) {
apps::AddCommandItem(ash::UNINSTALL, IDS_APP_LIST_UNINSTALL_ITEM,
menu_items);
}
if (!web_app->IsSystemApp()) {
apps::AddCommandItem(ash::SHOW_APP_INFO, IDS_APP_CONTEXT_MENU_SHOW_INFO,
menu_items);
}
if (app_id == guest_os::kTerminalSystemAppId) {
guest_os::AddTerminalMenuShortcuts(profile_, ash::LAUNCH_APP_SHORTCUT_FIRST,
std::move(menu_items),
std::move(callback));
} else {
GetAppShortcutMenuModel(app_id, std::move(menu_items), std::move(callback));
}
}
#endif
void WebApps::UpdateAppSize(const std::string& app_id) { … }
void WebApps::SetWindowMode(const std::string& app_id,
apps::WindowMode window_mode) { … }
void WebApps::OpenNativeSettings(const std::string& app_id) { … }
void WebApps::PublishWebApps(std::vector<apps::AppPtr> apps) { … }
void WebApps::PublishWebApp(apps::AppPtr app) { … }
void WebApps::ModifyWebAppCapabilityAccess(
const std::string& app_id,
std::optional<bool> accessing_camera,
std::optional<bool> accessing_microphone) { … }
std::vector<apps::AppPtr> WebApps::CreateWebApps() { … }
void WebApps::InitWebApps() { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
void WebApps::PauseApp(const std::string& app_id) {
publisher_helper().PauseApp(app_id);
}
void WebApps::UnpauseApp(const std::string& app_id) {
publisher_helper().UnpauseApp(app_id);
}
void WebApps::StopApp(const std::string& app_id) {
publisher_helper().StopApp(app_id);
}
void WebApps::GetAppShortcutMenuModel(
const std::string& app_id,
apps::MenuItems menu_items,
base::OnceCallback<void(apps::MenuItems)> callback) {
const WebApp* web_app = GetWebApp(app_id);
if (!web_app) {
std::move(callback).Run(apps::MenuItems());
return;
}
if (!web_app->shortcuts_menu_item_infos().empty()) {
provider()->icon_manager().ReadAllShortcutsMenuIcons(
app_id, base::BindOnce(&WebApps::OnShortcutsMenuIconsRead,
weak_ptr_factory_.GetWeakPtr(), app_id,
std::move(menu_items), std::move(callback)));
} else {
std::move(callback).Run(std::move(menu_items));
}
}
void WebApps::OnShortcutsMenuIconsRead(
const std::string& app_id,
apps::MenuItems menu_items,
base::OnceCallback<void(apps::MenuItems)> callback,
ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps) {
const WebApp* web_app = GetWebApp(app_id);
if (!web_app) {
std::move(callback).Run(apps::MenuItems());
return;
}
apps::AddSeparator(ui::DOUBLE_SEPARATOR, menu_items);
size_t menu_item_index = 0;
for (const WebAppShortcutsMenuItemInfo& menu_item_info :
web_app->shortcuts_menu_item_infos()) {
const std::map<SquareSizePx, SkBitmap>* menu_item_icon_bitmaps = nullptr;
if (menu_item_index < shortcuts_menu_icon_bitmaps.size()) {
menu_item_icon_bitmaps =
&shortcuts_menu_icon_bitmaps[menu_item_index].maskable;
if (menu_item_icon_bitmaps->empty()) {
menu_item_icon_bitmaps =
&shortcuts_menu_icon_bitmaps[menu_item_index].any;
}
}
if (menu_item_index != 0) {
apps::AddSeparator(ui::PADDED_SEPARATOR, menu_items);
}
gfx::ImageSkia icon;
if (menu_item_icon_bitmaps) {
IconEffects icon_effects = IconEffects::kNone;
icon_effects = apps::kCrOsStandardBackground | apps::kCrOsStandardMask;
icon = ConvertSquareBitmapsToImageSkia(
*menu_item_icon_bitmaps, icon_effects,
apps::kAppShortcutIconSizeDip);
}
const int command_id = ash::LAUNCH_APP_SHORTCUT_FIRST + menu_item_index;
const std::string label = base::UTF16ToUTF8(menu_item_info.name);
std::string shortcut_id = publisher_helper().GenerateShortcutId();
publisher_helper().StoreShortcutId(shortcut_id, menu_item_info);
apps::AddShortcutCommandItem(command_id, shortcut_id, label, icon,
menu_items);
++menu_item_index;
}
std::move(callback).Run(std::move(menu_items));
}
void WebApps::ExecuteContextMenuCommand(const std::string& app_id,
int command_id,
const std::string& shortcut_id,
int64_t display_id) {
if (app_id == guest_os::kTerminalSystemAppId) {
if (guest_os::ExecuteTerminalMenuShortcutCommand(profile_, shortcut_id,
display_id)) {
return;
}
}
publisher_helper().ExecuteContextMenuCommand(app_id, shortcut_id, display_id,
base::DoNothing());
}
void WebApps::LaunchMallWithContext(int32_t event_flags,
apps::LaunchSource launch_source,
apps::WindowInfoPtr window_info,
apps::DeviceInfo device_info) {
LaunchAppWithIntent(
kMallAppId, event_flags,
std::make_unique<apps::Intent>(apps_util::kIntentActionView,
ash::GetMallLaunchUrl(device_info)),
launch_source, std::move(window_info), base::DoNothing());
}
#endif
}