// Copyright 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 "ash/accelerators/exit_warning_handler.h" #include #include "ash/public/cpp/shell_window_ids.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" #include "ui/gfx/text_utils.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" namespace ash { namespace { const int64_t kTimeOutMilliseconds = 2000; // Color of the text of the warning message. const SkColor kTextColor = SK_ColorWHITE; // Color of the window background. const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0); // Radius of the rounded corners of the window. const int kWindowCornerRadius = 2; const int kHorizontalMarginAroundText = 100; const int kVerticalMarginAroundText = 100; class ExitWarningWidgetDelegateView : public views::WidgetDelegateView { public: ExitWarningWidgetDelegateView() : text_(l10n_util::GetStringUTF16(IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT)), accessible_name_(l10n_util::GetStringUTF16( IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT_ACCESSIBLE)), text_width_(0) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); const gfx::FontList& font_list = rb.GetFontList(ui::ResourceBundle::LargeFont); text_width_ = gfx::GetStringWidth(text_, font_list); SetPreferredSize( gfx::Size(text_width_ + kHorizontalMarginAroundText, font_list.GetHeight() + kVerticalMarginAroundText)); auto label = std::make_unique(); label->SetText(text_); label->SetHorizontalAlignment(gfx::ALIGN_CENTER); label->SetFontList(font_list); label->SetEnabledColor(kTextColor); label->SetAutoColorReadabilityEnabled(false); label->SetSubpixelRenderingEnabled(false); AddChildView(std::move(label)); SetLayoutManager(std::make_unique()); } ExitWarningWidgetDelegateView(const ExitWarningWidgetDelegateView&) = delete; ExitWarningWidgetDelegateView& operator=( const ExitWarningWidgetDelegateView&) = delete; void OnPaint(gfx::Canvas* canvas) override { cc::PaintFlags flags; flags.setStyle(cc::PaintFlags::kFill_Style); flags.setColor(kWindowBackgroundColor); canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, flags); views::WidgetDelegateView::OnPaint(canvas); } void GetAccessibleNodeData(ui::AXNodeData* node_data) override { node_data->role = ax::mojom::Role::kAlert; node_data->SetName(accessible_name_); } private: std::u16string text_; std::u16string accessible_name_; int text_width_; }; } // namespace ExitWarningHandler::ExitWarningHandler() : state_(IDLE), stub_timer_for_test_(false) {} ExitWarningHandler::~ExitWarningHandler() { // Note: If a timer is outstanding, it is stopped in its destructor. Hide(); } void ExitWarningHandler::HandleAccelerator() { switch (state_) { case IDLE: state_ = WAIT_FOR_DOUBLE_PRESS; Show(); StartTimer(); base::RecordAction(base::UserMetricsAction("Accel_Exit_First_Q")); break; case WAIT_FOR_DOUBLE_PRESS: state_ = EXITING; CancelTimer(); Hide(); base::RecordAction(base::UserMetricsAction("Accel_Exit_Second_Q")); Shell::Get()->session_controller()->RequestSignOut(); break; case EXITING: break; } } void ExitWarningHandler::TimerAction() { Hide(); if (state_ == WAIT_FOR_DOUBLE_PRESS) state_ = IDLE; } void ExitWarningHandler::StartTimer() { if (stub_timer_for_test_) return; timer_.Start(FROM_HERE, base::Milliseconds(kTimeOutMilliseconds), this, &ExitWarningHandler::TimerAction); } void ExitWarningHandler::CancelTimer() { timer_.Stop(); } void ExitWarningHandler::Show() { if (widget_) return; aura::Window* root_window = Shell::GetRootWindowForNewWindows(); ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView; gfx::Size rs = root_window->bounds().size(); gfx::Size ps = delegate->GetPreferredSize(); gfx::Rect bounds((rs.width() - ps.width()) / 2, (rs.height() - ps.height()) / 3, ps.width(), ps.height()); views::Widget::InitParams params; params.type = views::Widget::InitParams::TYPE_POPUP; params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.accept_events = false; params.z_order = ui::ZOrderLevel::kFloatingUIElement; params.delegate = delegate; params.bounds = bounds; params.name = "ExitWarningWindow"; params.parent = root_window->GetChildById(kShellWindowId_SettingBubbleContainer); widget_ = std::make_unique(); widget_->Init(std::move(params)); widget_->Show(); delegate->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true); } void ExitWarningHandler::Hide() { widget_.reset(); } } // namespace ash