blob: 1df56773e3787378f56d037b3388ba4bf9205677 [file] [log] [blame]
// Copyright (c) 2013 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/outdated_upgrade_bubble_view.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/views/elevation_icon_setter.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/user_metrics.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include "chrome/installer/util/google_update_util.h"
#endif
namespace {
// Fixed width of the description label of the bubble.
// TODO(mad): Make sure there is enough room for all languages.
const int kWidthOfDescriptionText = 330;
// The URL to be used to re-install Chrome when auto-update failed for too long.
const char kDownloadChromeUrl[] = "https://www.google.com/chrome/?&brand=CHWL"
"&utm_campaign=en&utm_source=en-et-na-us-chrome-bubble&utm_medium=et";
// The maximum number of ignored bubble we track in the NumLaterPerReinstall
// histogram.
const int kMaxIgnored = 50;
// The number of buckets we want the NumLaterPerReinstall histogram to use.
const int kNumIgnoredBuckets = 5;
// The currently showing bubble.
OutdatedUpgradeBubbleView* g_upgrade_bubble = nullptr;
// The number of times the user ignored the bubble before finally choosing to
// reinstall.
int g_num_ignored_bubbles = 0;
} // namespace
// OutdatedUpgradeBubbleView ---------------------------------------------------
// static
void OutdatedUpgradeBubbleView::ShowBubble(views::View* anchor_view,
content::PageNavigator* navigator,
bool auto_update_enabled) {
if (g_upgrade_bubble)
return;
g_upgrade_bubble = new OutdatedUpgradeBubbleView(anchor_view, navigator,
auto_update_enabled);
views::BubbleDialogDelegateView::CreateBubble(g_upgrade_bubble)->Show();
content::RecordAction(auto_update_enabled ?
base::UserMetricsAction("OutdatedUpgradeBubble.Show") :
base::UserMetricsAction("OutdatedUpgradeBubble.ShowNoAU"));
}
bool OutdatedUpgradeBubbleView::IsAvailable() {
// This should only work on non-Chrome OS desktop platforms.
#if defined(OS_WIN) || defined(OS_MACOSX) || \
(defined(OS_LINUX) && !defined(OS_CHROMEOS))
return true;
#else
return false;
#endif
}
OutdatedUpgradeBubbleView::~OutdatedUpgradeBubbleView() {
// Increment the ignored bubble count (if this bubble wasn't ignored, this
// increment is offset by a decrement in Accept()).
if (g_num_ignored_bubbles < kMaxIgnored)
++g_num_ignored_bubbles;
}
void OutdatedUpgradeBubbleView::WindowClosing() {
// Reset |g_upgrade_bubble| here, not in destructor, because destruction is
// asynchronous and ShowBubble may be called before full destruction and
// would attempt to show a bubble that is closing.
DCHECK_EQ(g_upgrade_bubble, this);
g_upgrade_bubble = nullptr;
}
base::string16 OutdatedUpgradeBubbleView::GetWindowTitle() const {
return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TITLE);
}
gfx::ImageSkia OutdatedUpgradeBubbleView::GetWindowIcon() {
return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_UPDATE_MENU_SEVERITY_HIGH);
}
bool OutdatedUpgradeBubbleView::ShouldShowWindowIcon() const {
return true;
}
bool OutdatedUpgradeBubbleView::Cancel() {
content::RecordAction(base::UserMetricsAction("OutdatedUpgradeBubble.Later"));
return true;
}
bool OutdatedUpgradeBubbleView::Accept() {
// Offset the +1 in the dtor.
--g_num_ignored_bubbles;
if (auto_update_enabled_) {
DCHECK(UpgradeDetector::GetInstance()->is_outdated_install());
UMA_HISTOGRAM_CUSTOM_COUNTS("OutdatedUpgradeBubble.NumLaterPerReinstall",
g_num_ignored_bubbles, 1, kMaxIgnored,
kNumIgnoredBuckets);
content::RecordAction(
base::UserMetricsAction("OutdatedUpgradeBubble.Reinstall"));
navigator_->OpenURL(
content::OpenURLParams(GURL(kDownloadChromeUrl), content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, false));
#if defined(OS_WIN)
} else {
DCHECK(UpgradeDetector::GetInstance()->is_outdated_install_no_au());
UMA_HISTOGRAM_CUSTOM_COUNTS("OutdatedUpgradeBubble.NumLaterPerEnableAU",
g_num_ignored_bubbles, 1, kMaxIgnored,
kNumIgnoredBuckets);
content::RecordAction(
base::UserMetricsAction("OutdatedUpgradeBubble.EnableAU"));
// Record that the autoupdate flavour of the dialog has been shown.
if (g_browser_process->local_state()) {
g_browser_process->local_state()->SetBoolean(
prefs::kAttemptedToEnableAutoupdate, true);
}
// Re-enable updates by shelling out to setup.exe in the blocking pool.
content::BrowserThread::PostBlockingPoolTask(
FROM_HERE,
base::Bind(&google_update::ElevateIfNeededToReenableUpdates));
#endif // defined(OS_WIN)
}
return true;
}
void OutdatedUpgradeBubbleView::UpdateButton(views::LabelButton* button,
ui::DialogButton type) {
BubbleDialogDelegateView::UpdateButton(button, type);
if (type == ui::DIALOG_BUTTON_OK) {
elevation_icon_setter_.reset(new ElevationIconSetter(
button, base::Bind(&OutdatedUpgradeBubbleView::SizeToContents,
base::Unretained(this))));
}
}
base::string16 OutdatedUpgradeBubbleView::GetDialogButtonLabel(
ui::DialogButton button) const {
return l10n_util::GetStringUTF16(
button == ui::DIALOG_BUTTON_CANCEL
? IDS_LATER
: auto_update_enabled_ ? IDS_REINSTALL_APP : IDS_REENABLE_UPDATES);
}
void OutdatedUpgradeBubbleView::Init() {
SetLayoutManager(new views::FillLayout());
views::Label* text_label = new views::Label(l10n_util::GetStringUTF16(
auto_update_enabled_ ? IDS_UPGRADE_BUBBLE_TEXT
: IDS_UPGRADE_BUBBLE_REENABLE_TEXT));
text_label->SetMultiLine(true);
text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
text_label->SizeToFit(kWidthOfDescriptionText);
AddChildView(text_label);
}
OutdatedUpgradeBubbleView::OutdatedUpgradeBubbleView(
views::View* anchor_view,
content::PageNavigator* navigator,
bool auto_update_enabled)
: BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
auto_update_enabled_(auto_update_enabled),
navigator_(navigator) {
// Compensate for built-in vertical padding in the anchor view's image.
set_anchor_view_insets(gfx::Insets(
GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0));
}