Commit 83067a67 authored by nancy's avatar nancy Committed by Commit Bot

Add uninstall_dialog to AppService.

Design doc: go/chrome-general-app-uninstallation-dialog

This is the first CL to add the unified uninstall_dialog in AppService.
There are several features not involved in this CL, and they will be
done by separate CLs:
1. Add Crostini uninstall function.
2. Add an interface to the uninstall, like what is done by
extension_uninstall_dialog_->ConfirmUninstallByExtension
3. Add RecordDialogCreation to the appropriate place as what is done by
extension_uninstall_dialog.
4. Add UMA to the appropriate place as what is done by
extension_uninstall_dialog.

This CL should not change any current behavior as AppServiceProxy still
call the old Uninstall to conduct uninstall action. A separate CL will
be used to update AppServiceProxy to use this CL as that is more easy
to rollback, since this CL is L size.

BUG=1009248

Change-Id: I2c1adead34c62e2fe67690e696a83070192ffc46
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1833024
Commit-Queue: Nancy Wang <nancylingwang@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarNigel Tao <nigeltao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705897}
parent 7b8c50bc
......@@ -2934,6 +2934,8 @@ jumbo_split_static_library("browser") {
"apps/app_service/app_service_proxy_factory.h",
"apps/app_service/dip_px_util.cc",
"apps/app_service/dip_px_util.h",
"apps/app_service/uninstall_dialog.cc",
"apps/app_service/uninstall_dialog.h",
"apps/intent_helper/apps_navigation_throttle.cc",
"apps/intent_helper/apps_navigation_throttle.h",
"apps/intent_helper/apps_navigation_types.cc",
......
......@@ -12,6 +12,7 @@
#include "chrome/browser/apps/app_service/app_icon_source.h"
#include "chrome/browser/apps/app_service/app_service_metrics.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/uninstall_dialog.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/services/app_service/app_service_impl.h"
#include "chrome/services/app_service/public/cpp/intent_util.h"
......@@ -211,11 +212,27 @@ void AppServiceProxy::SetPermission(const std::string& app_id,
void AppServiceProxy::Uninstall(const std::string& app_id) {
if (app_service_.is_connected()) {
cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) {
app_service_->Uninstall(update.AppType(), update.AppId());
app_service_->PromptUninstall(update.AppType(), update.AppId());
});
}
}
void AppServiceProxy::OnUninstallDialogClosed(
apps::mojom::AppType app_type,
const std::string& app_id,
bool uninstall,
bool clear_site_data,
bool report_abuse,
UninstallDialog* uninstall_dialog) {
if (uninstall)
app_service_->Uninstall(app_type, app_id, clear_site_data, report_abuse);
DCHECK(uninstall_dialog);
auto it = uninstall_dialogs_.find(uninstall_dialog);
DCHECK(it != uninstall_dialogs_.end());
uninstall_dialogs_.erase(it);
}
void AppServiceProxy::OpenNativeSettings(const std::string& app_id) {
if (app_service_.is_connected()) {
cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) {
......@@ -289,6 +306,8 @@ void AppServiceProxy::AddAppIconSource(Profile* profile) {
}
void AppServiceProxy::Shutdown() {
uninstall_dialogs_.clear();
#if defined(OS_CHROMEOS)
if (app_service_.is_connected()) {
extension_apps_->Shutdown();
......
......@@ -6,9 +6,12 @@
#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
#include <memory>
#include <set>
#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/apps/app_service/uninstall_dialog.h"
#include "chrome/services/app_service/public/cpp/app_registry_cache.h"
#include "chrome/services/app_service/public/cpp/icon_cache.h"
#include "chrome/services/app_service/public/cpp/icon_coalescer.h"
......@@ -75,6 +78,12 @@ class AppServiceProxy : public KeyedService,
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission);
void Uninstall(const std::string& app_id);
void OnUninstallDialogClosed(apps::mojom::AppType app_type,
const std::string& app_id,
bool uninstall,
bool clear_site_data,
bool report_abuse,
UninstallDialog* uninstall_dialog);
void OpenNativeSettings(const std::string& app_id);
void FlushMojoCallsForTesting();
......@@ -187,6 +196,10 @@ class AppServiceProxy : public KeyedService,
Profile* profile_;
using UninstallDialogs = std::set<std::unique_ptr<apps::UninstallDialog>,
base::UniquePtrComparator>;
UninstallDialogs uninstall_dialogs_;
base::WeakPtrFactory<AppServiceProxy> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AppServiceProxy);
......
......@@ -396,13 +396,19 @@ void ArcApps::SetPermission(const std::string& app_id,
}
}
void ArcApps::Uninstall(const std::string& app_id) {
void ArcApps::PromptUninstall(const std::string& app_id) {
if (!profile_) {
return;
}
arc::ShowArcAppUninstallDialog(profile_, nullptr /* controller */, app_id);
}
void ArcApps::Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) {
arc::UninstallArcApp(app_id, profile_);
}
void ArcApps::OpenNativeSettings(const std::string& app_id) {
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_);
if (!prefs) {
......
......@@ -73,7 +73,10 @@ class ArcApps : public KeyedService,
int64_t display_id) override;
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
void Uninstall(const std::string& app_id) override;
void PromptUninstall(const std::string& app_id) override;
void Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) override;
void OpenNativeSettings(const std::string& app_id) override;
// ArcAppListPrefs::Observer overrides.
......
......@@ -174,7 +174,15 @@ void BuiltInChromeOsApps::SetPermission(const std::string& app_id,
NOTIMPLEMENTED();
}
void BuiltInChromeOsApps::Uninstall(const std::string& app_id) {
void BuiltInChromeOsApps::PromptUninstall(const std::string& app_id) {
constexpr bool kClearSiteData = false;
constexpr bool kReportAbuse = false;
Uninstall(app_id, kClearSiteData, kReportAbuse);
}
void BuiltInChromeOsApps::Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) {
LOG(ERROR) << "Uninstall failed, could not remove built-in app with id "
<< app_id;
}
......
......@@ -52,7 +52,10 @@ class BuiltInChromeOsApps : public apps::mojom::Publisher {
int64_t display_id) override;
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
void Uninstall(const std::string& app_id) override;
void PromptUninstall(const std::string& app_id) override;
void Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) override;
void OpenNativeSettings(const std::string& app_id) override;
mojo::Receiver<apps::mojom::Publisher> receiver_{this};
......
......@@ -152,7 +152,13 @@ void CrostiniApps::SetPermission(const std::string& app_id,
NOTIMPLEMENTED();
}
void CrostiniApps::Uninstall(const std::string& app_id) {
void CrostiniApps::PromptUninstall(const std::string& app_id) {
NOTIMPLEMENTED();
}
void CrostiniApps::Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) {
NOTIMPLEMENTED();
}
......
......@@ -70,7 +70,10 @@ class CrostiniApps : public KeyedService,
int64_t display_id) override;
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
void Uninstall(const std::string& app_id) override;
void PromptUninstall(const std::string& app_id) override;
void Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) override;
void OpenNativeSettings(const std::string& app_id) override;
// CrostiniRegistryService::Observer overrides.
......
......@@ -43,8 +43,10 @@
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/browser/clear_site_data_utils.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/switches.h"
#include "url/url_constants.h"
......@@ -403,7 +405,7 @@ void ExtensionApps::SetPermission(const std::string& app_id,
permission_value);
}
void ExtensionApps::Uninstall(const std::string& app_id) {
void ExtensionApps::PromptUninstall(const std::string& app_id) {
if (!profile_) {
return;
}
......@@ -414,6 +416,60 @@ void ExtensionApps::Uninstall(const std::string& app_id) {
uninstaller->Run();
}
void ExtensionApps::Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) {
// TODO(crbug.com/1009248): We need to add the error code, which could be used
// by ExtensionFunction, ManagementUninstallFunctionBase on the callback
// OnExtensionUninstallDialogClosed
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
app_id);
if (!extension) {
return;
}
base::string16 error;
extensions::ExtensionSystem::Get(profile_)
->extension_service()
->UninstallExtension(
app_id, extensions::UninstallReason::UNINSTALL_REASON_USER_INITIATED,
&error);
if (!clear_site_data) {
return;
}
if (extension->from_bookmark()) {
constexpr bool kClearCookies = true;
constexpr bool kClearStorage = true;
constexpr bool kClearCache = true;
constexpr bool kAvoidClosingConnections = false;
content::ClearSiteData(
base::BindRepeating(
[](content::BrowserContext* browser_context) {
return browser_context;
},
base::Unretained(profile_)),
url::Origin::Create(
extensions::AppLaunchInfo::GetFullLaunchURL(extension)),
kClearCookies, kClearStorage, kClearCache, kAvoidClosingConnections,
base::DoNothing());
} else {
// If the extension specifies a custom uninstall page via
// chrome.runtime.setUninstallURL, then at uninstallation its uninstall
// page opens. To ensure that the CWS Report Abuse page is the active
// tab at uninstallation, navigates to the url to report abuse.
constexpr char kReferrerId[] = "chrome-remove-extension-dialog";
NavigateParams params(
profile_,
extension_urls::GetWebstoreReportAbuseUrl(app_id, kReferrerId),
ui::PAGE_TRANSITION_LINK);
params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
Navigate(&params);
}
}
void ExtensionApps::OpenNativeSettings(const std::string& app_id) {
if (!profile_) {
return;
......
......@@ -84,7 +84,10 @@ class ExtensionApps : public apps::mojom::Publisher,
int64_t display_id) override;
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
void Uninstall(const std::string& app_id) override;
void PromptUninstall(const std::string& app_id) override;
void Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) override;
void OpenNativeSettings(const std::string& app_id) override;
// content_settings::Observer overrides.
......
// Copyright (c) 2019 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/apps/app_service/uninstall_dialog.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/services/app_service/public/cpp/icon_loader.h"
namespace apps {
UninstallDialog::UninstallDialog(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::IconLoader* icon_loader,
UninstallCallback uninstall_callback)
: profile_(profile),
app_type_(app_type),
app_id_(app_id),
uninstall_callback_(std::move(uninstall_callback)) {
constexpr bool kAllowPlaceholderIcon = false;
icon_loader->LoadIconFromIconKey(
app_type, app_id, std::move(icon_key),
apps::mojom::IconCompression::kUncompressed, kSizeHintInDip,
kAllowPlaceholderIcon,
base::BindOnce(&UninstallDialog::OnLoadIcon,
weak_ptr_factory_.GetWeakPtr()));
}
UninstallDialog::~UninstallDialog() = default;
void UninstallDialog::OnDialogClosed(bool uninstall,
bool clear_site_data,
bool report_abuse) {
std::move(uninstall_callback_)
.Run(uninstall, clear_site_data, report_abuse, this);
}
void UninstallDialog::OnLoadIcon(apps::mojom::IconValuePtr icon_value) {
if (icon_value->icon_compression !=
apps::mojom::IconCompression::kUncompressed) {
return;
}
UiBase::Create(profile_, app_type_, app_id_, icon_value->uncompressed, this);
}
} // namespace apps
// Copyright (c) 2019 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.
#ifndef CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
class Profile;
namespace gfx {
class ImageSkia;
}
namespace apps {
class IconLoader;
class UninstallDialog;
} // namespace apps
namespace apps {
// Currently, app uninstallation on Chrome OS invokes a specific dialog per app
// type, Chrome Apps / PWAs, ARC apps and Crostini. There are 3 separate views
// for app uninstalling, which are subtly different from each other.
//
// This UninstallDialog combines the above three specific dialogs, and based on
// different app type to generate different view. Once the user has confirmed,
// the App Service calls the publisher to uninstall the app directly.
//
// TODO(crbug.com/1009248):
// 1. Add an interface to the uninstall, like what is done by
// extension_uninstall_dialog_->ConfirmUninstallByExtension
// 2. Add RecordDialogCreation to the appropriate place as what is done by
// extension_uninstall_dialog.
// 3. Add UMA to the appropriate place as what is done by
// extension_uninstall_dialog.
class UninstallDialog {
public:
// The UiBase is the parent virtual class for the AppUninstallDialogView,
// which is located in
// chrome/browser/ui/view/apps/app_uninstall_dialog_view.h. The UiBase is also
// used to connect the UninstallDialog and AppUninstallDialogView, to transfer
// the icon image, and the callback function.
class UiBase {
public:
explicit UiBase(gfx::ImageSkia image, UninstallDialog* uninstall_dialog)
: image_(image), uninstall_dialog_(uninstall_dialog) {}
virtual ~UiBase() = default;
static void Create(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
gfx::ImageSkia image,
UninstallDialog* uninstall_dialog);
gfx::ImageSkia image() const { return image_; }
UninstallDialog* uninstall_dialog() const { return uninstall_dialog_; }
private:
gfx::ImageSkia image_;
UninstallDialog* uninstall_dialog_;
DISALLOW_COPY_AND_ASSIGN(UiBase);
};
// Called when the dialog closes after the user has made a decision about
// whether to uninstall the app. If |clear_site_data| is true, site data will
// be removed after uninstalling the app. Only ever true for PWAs. If
// |report_abuse| is true, report abuse after uninstalling the app. Only ever
// true for Chrome Apps.
using UninstallCallback =
base::OnceCallback<void(bool uninstall,
bool clear_site_data,
bool report_rebuse,
UninstallDialog* uninstall_dialog)>;
static constexpr int32_t kSizeHintInDip = 32;
UninstallDialog(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
IconLoader* icon_loader,
UninstallCallback uninstall_callback);
~UninstallDialog();
// Called when the uninstall dialog is closing to process uninstall or cancel
// the uninstall.
void OnDialogClosed(bool uninstall, bool clear_site_data, bool report_abuse);
private:
// Callback invoked when the icon is loaded.
void OnLoadIcon(apps::mojom::IconValuePtr icon_value);
Profile* profile_;
apps::mojom::AppType app_type_;
const std::string app_id_;
UninstallCallback uninstall_callback_;
base::WeakPtrFactory<UninstallDialog> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(UninstallDialog);
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_APP_SERVICE_UNINSTALL_DIALOG_H_
......@@ -2608,6 +2608,8 @@ jumbo_split_static_library("ui") {
"views/apps/app_info_dialog/app_info_permissions_panel.h",
"views/apps/app_info_dialog/app_info_summary_panel.cc",
"views/apps/app_info_dialog/app_info_summary_panel.h",
"views/apps/app_uninstall_dialog_view.cc",
"views/apps/app_uninstall_dialog_view.h",
"views/apps/chrome_native_app_window_views.cc",
"views/apps/chrome_native_app_window_views.h",
"views/autofill/autofill_bubble_handler_impl.cc",
......
// Copyright (c) 2019 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/views/apps/app_uninstall_dialog_view.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/elide_url.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/constants.h"
#include "extensions/common/manifest_url_handlers.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#endif
// static
void apps::UninstallDialog::UiBase::Create(
Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
gfx::ImageSkia image,
apps::UninstallDialog* uninstall_dialog) {
new AppUninstallDialogView(profile, app_type, app_id, image,
uninstall_dialog);
}
AppUninstallDialogView::AppUninstallDialogView(
Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
gfx::ImageSkia image,
apps::UninstallDialog* uninstall_dialog)
: apps::UninstallDialog::UiBase(image, uninstall_dialog),
BubbleDialogDelegateView(nullptr, views::BubbleBorder::NONE) {
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(),
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
// Add margins for the icon plus the icon-title padding so that the dialog
// contents align with the title text.
set_margins(
margins() +
gfx::Insets(0, margins().left() + apps::UninstallDialog::kSizeHintInDip,
0, 0));
InitializeView(profile, app_type, app_id);
constrained_window::CreateBrowserModalDialogViews(this, nullptr)->Show();
}
bool AppUninstallDialogView::Cancel() {
return Close();
}
bool AppUninstallDialogView::Accept() {
const bool clear_site_data =
clear_site_data_checkbox_ && clear_site_data_checkbox_->GetChecked();
const bool report_abuse_checkbox =
report_abuse_checkbox_ && report_abuse_checkbox_->GetChecked();
uninstall_dialog()->OnDialogClosed(true /* uninstall */, clear_site_data,
report_abuse_checkbox);
return true;
}
bool AppUninstallDialogView::Close() {
uninstall_dialog()->OnDialogClosed(false /* uninstall */,
false /* clear_site_data */,
false /* report_abuse */);
return true;
}
gfx::Size AppUninstallDialogView::CalculatePreferredSize() const {
const int default_width = views::LayoutProvider::Get()->GetDistanceMetric(
DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) -
margins().width();
return gfx::Size(default_width, GetHeightForWidth(default_width));
}
base::string16 AppUninstallDialogView::GetDialogButtonLabel(
ui::DialogButton button) const {
return button == ui::DIALOG_BUTTON_CANCEL ? cancel_button_text_
: confirm_button_text_;
}
ui::ModalType AppUninstallDialogView::GetModalType() const {
return ui::MODAL_TYPE_WINDOW;
}
gfx::ImageSkia AppUninstallDialogView::GetWindowIcon() {
return image();
}
base::string16 AppUninstallDialogView::GetWindowTitle() const {
return window_title_;
}
bool AppUninstallDialogView::ShouldShowCloseButton() const {
return false;
}
bool AppUninstallDialogView::ShouldShowWindowIcon() const {
return true;
}
void AppUninstallDialogView::AddMultiLineLabel(
views::View* parent,
const base::string16& label_text) {
auto* label =
parent->AddChildView(std::make_unique<views::Label>(label_text));
label->SetMultiLine(true);
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetAllowCharacterBreak(true);
}
void AppUninstallDialogView::InitializeViewForExtension(
Profile* profile,
const std::string& app_id) {
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
app_id);
DCHECK(extension);
window_title_ =
l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_TITLE,
base::UTF8ToUTF16(extension->name()));
confirm_button_text_ =
l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON);
if (extensions::ManifestURL::UpdatesFromGallery(extension)) {
auto report_abuse_checkbox = std::make_unique<views::Checkbox>(
l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_REPORT_ABUSE));
report_abuse_checkbox->SetMultiLine(true);
report_abuse_checkbox_ = AddChildView(std::move(report_abuse_checkbox));
} else if (extension->from_bookmark()) {
auto clear_site_data_checkbox =
std::make_unique<views::Checkbox>(l10n_util::GetStringFUTF16(
IDS_EXTENSION_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX,
url_formatter::FormatUrlForSecurityDisplay(
extensions::AppLaunchInfo::GetFullLaunchURL(extension),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)));
clear_site_data_checkbox->SetMultiLine(true);
clear_site_data_checkbox_ =
AddChildView(std::move(clear_site_data_checkbox));
}
}
#if defined(OS_CHROMEOS)
void AppUninstallDialogView::InitializeViewForArcApp(
Profile* profile,
const std::string& app_id) {
ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile);
DCHECK(arc_prefs);
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
arc_prefs->GetApp(app_id);
DCHECK(arc_prefs);
window_title_ = l10n_util::GetStringUTF16(
app_info->shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_TITLE
: IDS_APP_UNINSTALL_PROMPT_TITLE);
base::string16 heading_text = l10n_util::GetStringFUTF16(
app_info->shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_HEADING
: IDS_NON_PLATFORM_APP_UNINSTALL_PROMPT_HEADING,
base::UTF8ToUTF16(app_info->name));
base::string16 subheading_text;
if (!app_info->shortcut) {
subheading_text = l10n_util::GetStringUTF16(
IDS_ARC_APP_UNINSTALL_PROMPT_DATA_REMOVAL_WARNING);
}
confirm_button_text_ = l10n_util::GetStringUTF16(
app_info->shortcut ? IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON
: IDS_EXTENSION_PROMPT_UNINSTALL_APP_BUTTON);
auto* text_container = AddChildView(std::make_unique<views::View>());
auto* text_container_layout =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
text_container_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
text_container_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStart);
AddMultiLineLabel(text_container, heading_text);
if (!subheading_text.empty())
AddMultiLineLabel(text_container, subheading_text);
}
#endif
void AppUninstallDialogView::InitializeView(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id) {
cancel_button_text_ = l10n_util::GetStringUTF16(IDS_CANCEL);
switch (app_type) {
case apps::mojom::AppType::kUnknown:
case apps::mojom::AppType::kBuiltIn:
NOTREACHED();
break;
case apps::mojom::AppType::kArc:
#if defined(OS_CHROMEOS)
InitializeViewForArcApp(profile, app_id);
#endif
break;
case apps::mojom::AppType::kCrostini:
NOTREACHED();
break;
case apps::mojom::AppType::kExtension:
case apps::mojom::AppType::kWeb:
InitializeViewForExtension(profile, app_id);
break;
}
}
// Copyright (c) 2019 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.
#ifndef CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
#include <memory>
#include "base/macros.h"
#include "chrome/browser/apps/app_service/uninstall_dialog.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
class Profile;
namespace views {
class Checkbox;
} // namespace views
namespace gfx {
class ImageSkia;
}
// Currently, app uninstallation on Chrome OS invokes a specific dialog per app
// type:
// - Chrome Apps / PWAs:
// https://cs.chromium.org/chromium/src/chrome/browser/ui/app_list/extension_uninstaller.h?q=extensionuninstaller&sq=package:chromium&l=17
// - ARC apps:
// https://cs.chromium.org/chromium/src/chrome/browser/ui/app_list/arc/arc_app_dialog.h?q=arcappunin&sq=package:chromium&l=21
// - Crostini:
// https://cs.chromium.org/chromium/src/chrome/browser/chromeos/crostini/crostini_util.h?type=cs&q=crostiniuninstall&sq=package:chromium&g=0&l=131
//
// There are 3 separate views for app uninstalling, which are subtly different
// from each other.
//
// This class combines the above three specific dialogs, and generates the
// correct UI based on the app type. Once the user has confirmed the uninstall,
// this class calls the parent class apps::UninstallDialog::UiBase to notify
// AppService, which transfers control to the publisher to uninstall the app.
//
// TODO(crbug.com/1009248):
// 1. Add Crostini uninstall function.
// 2. Add an interface to the uninstall, like what is done by
// extension_uninstall_dialog_->ConfirmUninstallByExtension.
class AppUninstallDialogView : public apps::UninstallDialog::UiBase,
views::BubbleDialogDelegateView {
public:
AppUninstallDialogView(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id,
gfx::ImageSkia image,
apps::UninstallDialog* uninstall_dialog);
~AppUninstallDialogView() override = default;
// views::BubbleDialogDelegateView:
bool Cancel() override;
bool Accept() override;
bool Close() override;
gfx::Size CalculatePreferredSize() const override;
base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
ui::ModalType GetModalType() const override;
gfx::ImageSkia GetWindowIcon() override;
base::string16 GetWindowTitle() const override;
bool ShouldShowCloseButton() const override;
bool ShouldShowWindowIcon() const override;
private:
void AddMultiLineLabel(views::View* parent, const base::string16& label_text);
void InitializeViewForExtension(Profile* profile, const std::string& app_id);
#if defined(OS_CHROMEOS)
void InitializeViewForArcApp(Profile* profile, const std::string& app_id);
#endif
void InitializeView(Profile* profile,
apps::mojom::AppType app_type,
const std::string& app_id);
views::Checkbox* report_abuse_checkbox_ = nullptr;
views::Checkbox* clear_site_data_checkbox_ = nullptr;
// TODO(crbug.com/1009248): Remove these fields to use the consistent title
// and button.
base::string16 window_title_;
base::string16 confirm_button_text_;
base::string16 cancel_button_text_;
DISALLOW_COPY_AND_ASSIGN(AppUninstallDialogView);
};
#endif // CHROME_BROWSER_UI_VIEWS_APPS_APP_UNINSTALL_DIALOG_VIEW_H_
......@@ -126,13 +126,24 @@ void AppServiceImpl::SetPermission(apps::mojom::AppType app_type,
iter->second->SetPermission(app_id, std::move(permission));
}
void AppServiceImpl::PromptUninstall(apps::mojom::AppType app_type,
const std::string& app_id) {
auto iter = publishers_.find(app_type);
if (iter == publishers_.end()) {
return;
}
iter->second->PromptUninstall(app_id);
}
void AppServiceImpl::Uninstall(apps::mojom::AppType app_type,
const std::string& app_id) {
const std::string& app_id,
bool clear_site_data,
bool report_abuse) {
auto iter = publishers_.find(app_type);
if (iter == publishers_.end()) {
return;
}
iter->second->Uninstall(app_id);
iter->second->Uninstall(app_id, clear_site_data, report_abuse);
}
void AppServiceImpl::OpenNativeSettings(apps::mojom::AppType app_type,
......
......@@ -56,8 +56,12 @@ class AppServiceImpl : public apps::mojom::AppService {
void SetPermission(apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::PermissionPtr permission) override;
void PromptUninstall(apps::mojom::AppType app_type,
const std::string& app_id) override;
void Uninstall(apps::mojom::AppType app_type,
const std::string& app_id) override;
const std::string& app_id,
bool clear_site_data,
bool report_abuse) override;
void OpenNativeSettings(apps::mojom::AppType app_type,
const std::string& app_id) override;
......
......@@ -76,7 +76,10 @@ class FakePublisher : public apps::mojom::Publisher {
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission) override {}
void Uninstall(const std::string& app_id) override {}
void PromptUninstall(const std::string& app_id) override {}
void Uninstall(const std::string& app_id,
bool clear_site_data,
bool report_abuse) override {}
void OpenNativeSettings(const std::string& app_id) override {}
......
......@@ -53,10 +53,23 @@ interface AppService {
string app_id,
Permission permission);
Uninstall(
// Uninstall which invokes a specific dialog per app type. When the unified
// uninstall dialog is done, this interface will be removed.
PromptUninstall(
AppType app_type,
string app_id);
// Directly uninstalls |app_id| without prompting the user.
// |clear_site_data| is available for bookmark apps only. If true, any site
// data associated with the app will be removed..
// |report_abuse| is available for Chrome Apps only. If true, the app will be
// reported for abuse to the Web Store.
Uninstall(
AppType app_type,
string app_id,
bool clear_site_data,
bool report_abuse);
OpenNativeSettings(
AppType app_type,
string app_id);
......@@ -93,9 +106,21 @@ interface Publisher {
string app_id,
Permission permission);
Uninstall(
// Uninstall which invokes a specific dialog per app type. When the unified
// uninstall dialog is done, this interface will be removed.
PromptUninstall(
string app_id);
// Directly uninstalls |app_id| without prompting the user.
// |clear_site_data| is available for bookmark apps only. If true, any site
// data associated with the app will be removed..
// |report_abuse| is available for Chrome Apps only. If true, the app will be
// reported for abuse to the Web Store.
Uninstall(
string app_id,
bool clear_site_data,
bool report_abuse);
OpenNativeSettings(
string app_id);
};
......
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