Commit 5aed8804 authored by Ian Barkley-Yeung's avatar Ian Barkley-Yeung Committed by Commit Bot

Add uninstall menu option to Crostini apps

Add uninstall menu option to Crostini apps that can be uninstalled from
the container.

BUG=chromium:822514
TEST=Apps from .desktop files associated with a package now have
'uninstall' on right-click menu; Apps from .desktop files I created do
not have 'uninstall'

R=timloh@chromium.org

Change-Id: If7bcd69c08a806b98a4200d2de7ca4f550c57c21
Reviewed-on: https://chromium-review.googlesource.com/c/1213519
Commit-Queue: Ian Barkley-Yeung <iby@chromium.org>
Reviewed-by: default avatarTimothy Loh <timloh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612850}
parent 78744912
...@@ -49,6 +49,7 @@ constexpr char kAppMimeTypesKey[] = "mime_types"; ...@@ -49,6 +49,7 @@ constexpr char kAppMimeTypesKey[] = "mime_types";
constexpr char kAppNameKey[] = "name"; constexpr char kAppNameKey[] = "name";
constexpr char kAppNoDisplayKey[] = "no_display"; constexpr char kAppNoDisplayKey[] = "no_display";
constexpr char kAppScaledKey[] = "scaled"; constexpr char kAppScaledKey[] = "scaled";
constexpr char kAppPackageIdKey[] = "package_id";
constexpr char kAppStartupWMClassKey[] = "startup_wm_class"; constexpr char kAppStartupWMClassKey[] = "startup_wm_class";
constexpr char kAppStartupNotifyKey[] = "startup_notify"; constexpr char kAppStartupNotifyKey[] = "startup_notify";
constexpr char kAppInstallTimeKey[] = "install_time"; constexpr char kAppInstallTimeKey[] = "install_time";
...@@ -309,6 +310,26 @@ bool CrostiniRegistryService::Registration::NoDisplay() const { ...@@ -309,6 +310,26 @@ bool CrostiniRegistryService::Registration::NoDisplay() const {
return false; return false;
} }
bool CrostiniRegistryService::Registration::CanUninstall() const {
if (pref_.is_none())
return false;
// We can uninstall if and only if there is a package that owns the
// application. If no package owns the application, we don't know how to
// uninstall the app.
//
// We don't check other things that might prevent us from uninstalling the
// app. In particular, we don't check if there are other packages which
// depend on the owning package. This should be rare for packages that have
// desktop files, and it's better to show an error message (which the user can
// then Google to learn more) than to just not have an uninstall option at
// all.
const base::Value* package_id =
pref_.FindKeyOfType(kAppPackageIdKey, base::Value::Type::STRING);
if (package_id)
return !package_id->GetString().empty();
return false;
}
base::Time CrostiniRegistryService::Registration::InstallTime() const { base::Time CrostiniRegistryService::Registration::InstallTime() const {
return GetTime(pref_, kAppInstallTimeKey); return GetTime(pref_, kAppInstallTimeKey);
} }
...@@ -661,6 +682,7 @@ void CrostiniRegistryService::UpdateApplicationList( ...@@ -661,6 +682,7 @@ void CrostiniRegistryService::UpdateApplicationList(
base::Value(app.startup_wm_class())); base::Value(app.startup_wm_class()));
pref_registration.SetKey(kAppStartupNotifyKey, pref_registration.SetKey(kAppStartupNotifyKey,
base::Value(app.startup_notify())); base::Value(app.startup_notify()));
pref_registration.SetKey(kAppPackageIdKey, base::Value(app.package_id()));
base::Value* old_app = apps->FindKey(app_id); base::Value* old_app = apps->FindKey(app_id);
if (old_app && EqualsExcludingTimestamps(pref_registration, *old_app)) if (old_app && EqualsExcludingTimestamps(pref_registration, *old_app))
......
...@@ -90,6 +90,7 @@ class CrostiniRegistryService : public KeyedService { ...@@ -90,6 +90,7 @@ class CrostiniRegistryService : public KeyedService {
// Whether this app should scale up when displayed. // Whether this app should scale up when displayed.
bool IsScaled() const; bool IsScaled() const;
bool CanUninstall() const;
// Whether this app is the default terminal app. // Whether this app is the default terminal app.
bool is_terminal_app() const { return is_terminal_app_; } bool is_terminal_app() const { return is_terminal_app_; }
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
#include "ash/public/cpp/app_menu_constants.h" #include "ash/public/cpp/app_menu_constants.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
#include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
...@@ -18,17 +21,39 @@ CrostiniAppContextMenu::CrostiniAppContextMenu( ...@@ -18,17 +21,39 @@ CrostiniAppContextMenu::CrostiniAppContextMenu(
CrostiniAppContextMenu::~CrostiniAppContextMenu() = default; CrostiniAppContextMenu::~CrostiniAppContextMenu() = default;
// TODO(timloh): Add support for "App Info", "Uninstall", and possibly actions bool CrostiniAppContextMenu::IsUninstallable() const {
// defined in .desktop files. if (!crostini::IsCrostiniEnabled(profile())) {
return false;
}
if (app_id() == crostini::kCrostiniTerminalId) {
return true; // Crostini can always be uninstalled if enabled.
}
if (!base::FeatureList::IsEnabled(features::kCrostiniAppUninstallGui)) {
return false;
}
crostini::CrostiniRegistryService* registry_service =
crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
base::Optional<crostini::CrostiniRegistryService::Registration> registration =
registry_service->GetRegistration(app_id());
if (registration) {
return registration->CanUninstall();
}
return false;
}
// TODO(timloh): Add support for "App Info" and possibly actions defined in
// .desktop files.
void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) { void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
app_list::AppContextMenu::BuildMenu(menu_model); app_list::AppContextMenu::BuildMenu(menu_model);
if (app_id() == crostini::kCrostiniTerminalId) { if (IsUninstallable()) {
if (!features::IsTouchableAppContextMenuEnabled())
menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
AddContextMenuOption(menu_model, ash::UNINSTALL, AddContextMenuOption(menu_model, ash::UNINSTALL,
IDS_APP_LIST_UNINSTALL_ITEM); IDS_APP_LIST_UNINSTALL_ITEM);
}
if (app_id() == crostini::kCrostiniTerminalId) {
AddContextMenuOption(menu_model, ash::STOP_APP, AddContextMenuOption(menu_model, ash::STOP_APP,
IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM); IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM);
} }
...@@ -36,9 +61,7 @@ void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) { ...@@ -36,9 +61,7 @@ void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
bool CrostiniAppContextMenu::IsCommandIdEnabled(int command_id) const { bool CrostiniAppContextMenu::IsCommandIdEnabled(int command_id) const {
if (command_id == ash::UNINSTALL) { if (command_id == ash::UNINSTALL) {
if (app_id() == crostini::kCrostiniTerminalId) { return IsUninstallable();
return crostini::IsCrostiniEnabled(profile());
}
} else if (command_id == ash::STOP_APP) { } else if (command_id == ash::STOP_APP) {
if (app_id() == crostini::kCrostiniTerminalId) { if (app_id() == crostini::kCrostiniTerminalId) {
return crostini::IsCrostiniRunning(profile()); return crostini::IsCrostiniRunning(profile());
......
...@@ -27,6 +27,7 @@ class CrostiniAppContextMenu : public app_list::AppContextMenu { ...@@ -27,6 +27,7 @@ class CrostiniAppContextMenu : public app_list::AppContextMenu {
void BuildMenu(ui::SimpleMenuModel* menu_model) override; void BuildMenu(ui::SimpleMenuModel* menu_model) override;
private: private:
bool IsUninstallable() const;
DISALLOW_COPY_AND_ASSIGN(CrostiniAppContextMenu); DISALLOW_COPY_AND_ASSIGN(CrostiniAppContextMenu);
}; };
......
...@@ -184,6 +184,12 @@ const base::Feature kClipboardContentSetting{"ClipboardContentSetting", ...@@ -184,6 +184,12 @@ const base::Feature kClipboardContentSetting{"ClipboardContentSetting",
// Enable project Crostini, Linux VMs on Chrome OS. // Enable project Crostini, Linux VMs on Chrome OS.
const base::Feature kCrostini{"Crostini", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kCrostini{"Crostini", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables an uninstall option in the right-click menu of Crostini (Linux)
// applications.
// TODO(iby): Remove once remaining bugs fixed.
const base::Feature kCrostiniAppUninstallGui{"CrostiniAppUninstallGui",
base::FEATURE_DISABLED_BY_DEFAULT};
// Whether the UsageTimeLimit policy should be applied to the user. // Whether the UsageTimeLimit policy should be applied to the user.
const base::Feature kUsageTimeLimitPolicy{"UsageTimeLimitPolicy", const base::Feature kUsageTimeLimitPolicy{"UsageTimeLimitPolicy",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
......
...@@ -119,6 +119,8 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kContentFullscreen; ...@@ -119,6 +119,8 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kContentFullscreen;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostini; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostini;
COMPONENT_EXPORT(CHROME_FEATURES) COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kCrostiniAppUninstallGui;
COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kUsageTimeLimitPolicy; extern const base::Feature kUsageTimeLimitPolicy;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment