blob: 536a5c0a06cb30836f445947b3468e42e085567d [file] [log] [blame]
// Copyright 2014 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_info_dialog/app_info_footer_panel.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/generated_resources.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
#include "extensions/browser/uninstall_reason.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS)
// gn check complains on Linux Ozone.
#include "ash/public/cpp/shelf_model.h" // nogncheck
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
#endif
AppInfoFooterPanel::AppInfoFooterPanel(Profile* profile,
const extensions::Extension* app)
: AppInfoPanel(profile, app) {
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
provider->GetInsetsMetric(views::INSETS_DIALOG_SUBSECTION),
provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
CreateButtons();
}
AppInfoFooterPanel::~AppInfoFooterPanel() {
}
// static
std::unique_ptr<AppInfoFooterPanel> AppInfoFooterPanel::CreateFooterPanel(
Profile* profile,
const extensions::Extension* app) {
if (CanCreateShortcuts(app) ||
#if defined(OS_CHROMEOS)
CanSetPinnedToShelf(profile, app) ||
#endif
CanUninstallApp(profile, app))
return std::make_unique<AppInfoFooterPanel>(profile, app);
return nullptr;
}
void AppInfoFooterPanel::CreateButtons() {
if (CanCreateShortcuts(app_)) {
create_shortcuts_button_ =
AddChildView(std::make_unique<views::MdTextButton>(
this, l10n_util::GetStringUTF16(
IDS_APPLICATION_INFO_CREATE_SHORTCUTS_BUTTON_TEXT)));
}
#if defined(OS_CHROMEOS)
if (CanSetPinnedToShelf(profile_, app_)) {
pin_to_shelf_button_ = AddChildView(std::make_unique<views::MdTextButton>(
this, l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_PIN)));
unpin_from_shelf_button_ =
AddChildView(std::make_unique<views::MdTextButton>(
this, l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_UNPIN)));
UpdatePinButtons(false);
}
#endif
if (CanUninstallApp(profile_, app_)) {
remove_button_ = AddChildView(std::make_unique<views::MdTextButton>(
this,
l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_UNINSTALL_BUTTON_TEXT)));
}
}
#if defined(OS_CHROMEOS)
void AppInfoFooterPanel::UpdatePinButtons(bool focus_visible_button) {
if (pin_to_shelf_button_ && unpin_from_shelf_button_) {
const bool was_pinned =
ChromeLauncherController::instance()->shelf_model()->IsAppPinned(
app_->id());
pin_to_shelf_button_->SetVisible(!was_pinned);
unpin_from_shelf_button_->SetVisible(was_pinned);
if (focus_visible_button) {
views::View* button_to_focus =
was_pinned ? unpin_from_shelf_button_ : pin_to_shelf_button_;
button_to_focus->RequestFocus();
}
}
}
#endif
void AppInfoFooterPanel::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == create_shortcuts_button_) {
CreateShortcuts();
#if defined(OS_CHROMEOS)
} else if (sender == pin_to_shelf_button_) {
SetPinnedToShelf(true);
} else if (sender == unpin_from_shelf_button_) {
SetPinnedToShelf(false);
#endif
} else if (sender == remove_button_) {
UninstallApp();
} else {
NOTREACHED();
}
}
void AppInfoFooterPanel::OnExtensionUninstallDialogClosed(
bool did_start_uninstall,
const base::string16& error) {
if (did_start_uninstall) {
// Close the App Info dialog as well (which will free the dialog too).
Close();
} else {
extension_uninstall_dialog_.reset();
}
}
void AppInfoFooterPanel::CreateShortcuts() {
DCHECK(CanCreateShortcuts(app_));
chrome::ShowCreateChromeAppShortcutsDialog(GetWidget()->GetNativeWindow(),
profile_,
app_,
base::Callback<void(bool)>());
}
// static
bool AppInfoFooterPanel::CanCreateShortcuts(const extensions::Extension* app) {
#if defined(OS_CHROMEOS)
// Ash platforms can't create shortcuts.
return false;
#else
// Extensions and the Chrome component app can't have shortcuts.
return app->id() != extension_misc::kChromeAppId && !app->is_extension();
#endif // OS_CHROMEOS
}
#if defined(OS_CHROMEOS)
void AppInfoFooterPanel::SetPinnedToShelf(bool value) {
DCHECK(CanSetPinnedToShelf(profile_, app_));
ash::ShelfModel* shelf_model =
ChromeLauncherController::instance()->shelf_model();
DCHECK(shelf_model);
ash::ShelfModel::ScopedUserTriggeredMutation user_triggered(shelf_model);
if (value)
shelf_model->PinAppWithID(app_->id());
else
shelf_model->UnpinAppWithID(app_->id());
UpdatePinButtons(true);
Layout();
}
// static
bool AppInfoFooterPanel::CanSetPinnedToShelf(Profile* profile,
const extensions::Extension* app) {
// The Chrome app can't be unpinned, and extensions can't be pinned.
return app->id() != extension_misc::kChromeAppId && !app->is_extension() &&
(GetPinnableForAppID(app->id(), profile) ==
AppListControllerDelegate::PIN_EDITABLE);
}
#endif // OS_CHROMEOS
void AppInfoFooterPanel::UninstallApp() {
DCHECK(CanUninstallApp(profile_, app_));
extension_uninstall_dialog_ = extensions::ExtensionUninstallDialog::Create(
profile_, GetWidget()->GetNativeWindow(), this);
extension_uninstall_dialog_->ConfirmUninstall(
app_, extensions::UNINSTALL_REASON_USER_INITIATED,
extensions::UNINSTALL_SOURCE_APP_INFO_DIALOG);
}
// static
bool AppInfoFooterPanel::CanUninstallApp(Profile* profile,
const extensions::Extension* app) {
extensions::ManagementPolicy* policy =
extensions::ExtensionSystem::Get(profile)->management_policy();
return policy->UserMayModifySettings(app, nullptr) &&
!policy->MustRemainInstalled(app, nullptr);
}