blob: f6c8ec3ba6fb4871b1a59e5d67161428cea42ac1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/app_management/app_management_page_handler.h"
#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.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/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/app_management/app_management.mojom.h"
#include "chrome/services/app_service/public/cpp/app_registry_cache.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/permissions/permission_message.h"
#include "extensions/common/permissions/permissions_data.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/arc/arc_prefs.h"
#endif
using apps::mojom::OptionalBool;
namespace {
#if defined(OS_CHROMEOS)
constexpr char kArcFrameworkPackage[] = "android";
constexpr int kMinAndroidFrameworkVersion = 28; // Android P
#endif
constexpr char const* kAppIdsWithHiddenMoreSettings[] = {
extension_misc::kFilesManagerAppId,
extensions::kWebStoreAppId,
};
constexpr char const* kAppIdsWithHiddenPinToShelf[] = {
extension_misc::kChromeAppId,
};
#if defined(OS_CHROMEOS)
constexpr char const* kAppIdsWithHiddenStoragePermission[] = {
arc::kPlayStoreAppId,
};
#endif // OS_CHROMEOS
app_management::mojom::ExtensionAppPermissionMessagePtr
CreateExtensionAppPermissionMessage(
const extensions::PermissionMessage& message) {
std::vector<std::string> submessages;
for (const auto& submessage : message.submessages()) {
submessages.push_back(base::UTF16ToUTF8(submessage));
}
return app_management::mojom::ExtensionAppPermissionMessage::New(
base::UTF16ToUTF8(message.message()), std::move(submessages));
}
bool ShouldHideMoreSettings(const std::string app_id) {
return base::Contains(kAppIdsWithHiddenMoreSettings, app_id);
}
bool ShouldHidePinToShelf(const std::string app_id) {
return base::Contains(kAppIdsWithHiddenPinToShelf, app_id);
}
bool ShouldHideStoragePermission(const std::string app_id) {
#if defined(OS_CHROMEOS)
return base::Contains(kAppIdsWithHiddenStoragePermission, app_id);
#else
return false;
#endif
}
} // namespace
AppManagementPageHandler::AppManagementPageHandler(
mojo::PendingReceiver<app_management::mojom::PageHandler> receiver,
mojo::PendingRemote<app_management::mojom::Page> page,
Profile* profile)
: receiver_(this, std::move(receiver)),
page_(std::move(page)),
profile_(profile)
#if defined(OS_CHROMEOS)
,
arc_app_list_prefs_observer_(this),
shelf_delegate_(this)
#endif
{
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
Observe(&proxy->AppRegistryCache());
#if defined(OS_CHROMEOS)
if (arc::IsArcAllowedForProfile(profile_)) {
arc_app_list_prefs_observer_.Add(ArcAppListPrefs::Get(profile_));
}
#endif // OS_CHROMEOS
}
AppManagementPageHandler::~AppManagementPageHandler() {}
void AppManagementPageHandler::OnPinnedChanged(const std::string& app_id,
bool pinned) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
app_management::mojom::AppPtr app;
proxy->AppRegistryCache().ForOneApp(
app_id, [this, &app](const apps::AppUpdate& update) {
if (update.Readiness() == apps::mojom::Readiness::kReady)
app = CreateUIAppPtr(update);
});
// If an app with this id is not already installed, do nothing.
if (!app)
return;
app->is_pinned = pinned ? OptionalBool::kTrue : OptionalBool::kFalse;
page_->OnAppChanged(std::move(app));
}
void AppManagementPageHandler::GetApps(GetAppsCallback callback) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
std::vector<app_management::mojom::AppPtr> apps;
proxy->AppRegistryCache().ForEachApp(
[this, &apps](const apps::AppUpdate& update) {
if (update.ShowInManagement() == apps::mojom::OptionalBool::kTrue) {
apps.push_back(CreateUIAppPtr(update));
}
});
std::move(callback).Run(std::move(apps));
}
void AppManagementPageHandler::GetExtensionAppPermissionMessages(
const std::string& app_id,
GetExtensionAppPermissionMessagesCallback callback) {
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile_);
const extensions::Extension* extension = registry->GetExtensionById(
app_id, extensions::ExtensionRegistry::ENABLED |
extensions::ExtensionRegistry::DISABLED |
extensions::ExtensionRegistry::BLACKLISTED);
std::vector<app_management::mojom::ExtensionAppPermissionMessagePtr> messages;
if (extension) {
for (const auto& message :
extension->permissions_data()->GetPermissionMessages()) {
messages.push_back(CreateExtensionAppPermissionMessage(message));
}
}
std::move(callback).Run(std::move(messages));
}
void AppManagementPageHandler::SetPinned(const std::string& app_id,
OptionalBool pinned) {
#if defined(OS_CHROMEOS)
shelf_delegate_.SetPinned(app_id, pinned);
#else
NOTREACHED();
#endif
}
void AppManagementPageHandler::SetPermission(
const std::string& app_id,
apps::mojom::PermissionPtr permission) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
proxy->SetPermission(app_id, std::move(permission));
}
void AppManagementPageHandler::Uninstall(const std::string& app_id) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
proxy->Uninstall(app_id);
}
void AppManagementPageHandler::OpenNativeSettings(const std::string& app_id) {
apps::AppServiceProxy* proxy =
apps::AppServiceProxyFactory::GetForProfile(profile_);
// TODO(crbug.com/826982): revisit pending decision on AppServiceProxy in
// incognito
if (!proxy)
return;
proxy->OpenNativeSettings(app_id);
}
app_management::mojom::AppPtr AppManagementPageHandler::CreateUIAppPtr(
const apps::AppUpdate& update) {
base::flat_map<uint32_t, apps::mojom::PermissionPtr> permissions;
for (const auto& permission : update.Permissions()) {
if (static_cast<app_management::mojom::ArcPermissionType>(
permission->permission_id) ==
app_management::mojom::ArcPermissionType::STORAGE &&
ShouldHideStoragePermission(update.AppId())) {
continue;
}
permissions[permission->permission_id] = permission->Clone();
}
auto app = app_management::mojom::App::New();
app->id = update.AppId();
app->type = update.AppType();
app->title = update.Name();
app->permissions = std::move(permissions);
app->install_source = update.InstallSource();
app->description = update.Description();
// On other OS's, is_pinned defaults to OptionalBool::kUnknown, which is
// used to represent the fact that there is no concept of being pinned.
#if defined(OS_CHROMEOS)
app->is_pinned = shelf_delegate_.IsPinned(update.AppId())
? OptionalBool::kTrue
: OptionalBool::kFalse;
app->is_policy_pinned = shelf_delegate_.IsPolicyPinned(update.AppId())
? OptionalBool::kTrue
: OptionalBool::kFalse;
#endif
app->hide_more_settings = ShouldHideMoreSettings(app->id);
app->hide_pin_to_shelf = ShouldHidePinToShelf(app->id);
return app;
}
void AppManagementPageHandler::OnAppUpdate(const apps::AppUpdate& update) {
if (update.ShowInManagementChanged() || update.ReadinessChanged()) {
if (update.ShowInManagement() == apps::mojom::OptionalBool::kTrue &&
update.Readiness() == apps::mojom::Readiness::kReady) {
page_->OnAppAdded(CreateUIAppPtr(update));
}
if (update.ShowInManagement() == apps::mojom::OptionalBool::kFalse ||
update.Readiness() == apps::mojom::Readiness::kUninstalledByUser) {
page_->OnAppRemoved(update.AppId());
}
} else {
page_->OnAppChanged(CreateUIAppPtr(update));
}
}
void AppManagementPageHandler::OnAppRegistryCacheWillBeDestroyed(
apps::AppRegistryCache* cache) {
Observe(nullptr);
}
#if defined(OS_CHROMEOS)
// static
bool AppManagementPageHandler::IsCurrentArcVersionSupported(Profile* profile) {
if (arc::IsArcAllowedForProfile(profile)) {
auto package =
ArcAppListPrefs::Get(profile)->GetPackage(kArcFrameworkPackage);
return package && (package->package_version >= kMinAndroidFrameworkVersion);
}
return false;
}
void AppManagementPageHandler::OnArcVersionChanged(int androidVersion) {
page_->OnArcSupportChanged(androidVersion >= kMinAndroidFrameworkVersion);
}
void AppManagementPageHandler::OnPackageInstalled(
const arc::mojom::ArcPackageInfo& package_info) {
OnPackageModified(package_info);
}
void AppManagementPageHandler::OnPackageModified(
const arc::mojom::ArcPackageInfo& package_info) {
if (package_info.package_name != kArcFrameworkPackage) {
return;
}
OnArcVersionChanged(package_info.package_version);
}
#endif // OS_CHROMEOS