• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ash/accelerators/exit_warning_handler.h"
6 
7 #include "ash/metrics/user_metrics_recorder.h"
8 #include "ash/shell.h"
9 #include "ash/shell_delegate.h"
10 #include "ash/shell_window_ids.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "base/timer/timer.h"
14 #include "grit/ash_strings.h"
15 #include "ui/aura/window.h"
16 #include "ui/base/accessibility/accessible_view_state.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/font.h"
21 #include "ui/views/controls/label.h"
22 #include "ui/views/layout/fill_layout.h"
23 #include "ui/views/view.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/views/widget/widget_delegate.h"
26 
27 namespace ash {
28 namespace {
29 
30 const int64 kTimeOutMilliseconds = 2000;
31 // Color of the text of the warning message.
32 const SkColor kTextColor = SK_ColorWHITE;
33 // Color of the window background.
34 const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0);
35 // Radius of the rounded corners of the window.
36 const int kWindowCornerRadius = 2;
37 const int kHorizontalMarginAroundText = 100;
38 const int kVerticalMarginAroundText = 100;
39 
40 class ExitWarningLabel : public views::Label {
41  public:
ExitWarningLabel()42   ExitWarningLabel() {}
43 
~ExitWarningLabel()44   virtual ~ExitWarningLabel() {}
45 
46  private:
PaintText(gfx::Canvas * canvas,const string16 & text,const gfx::Rect & text_bounds,int flags)47   virtual void PaintText(gfx::Canvas* canvas,
48                          const string16& text,
49                          const gfx::Rect& text_bounds,
50                          int flags) OVERRIDE {
51     // Turn off subpixel rendering.
52     views::Label::PaintText(canvas,
53                             text,
54                             text_bounds,
55                             flags | gfx::Canvas::NO_SUBPIXEL_RENDERING);
56   }
57 
58   DISALLOW_COPY_AND_ASSIGN(ExitWarningLabel);
59 };
60 
61 class ExitWarningWidgetDelegateView : public views::WidgetDelegateView {
62  public:
ExitWarningWidgetDelegateView()63   ExitWarningWidgetDelegateView() : text_width_(0), width_(0), height_(0) {
64     text_ = l10n_util::GetStringUTF16(IDS_ASH_EXIT_WARNING_POPUP_TEXT);
65     accessible_name_ =
66         l10n_util::GetStringUTF16(IDS_ASH_EXIT_WARNING_POPUP_TEXT_ACCESSIBLE);
67     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
68     font_ = rb.GetFont(ui::ResourceBundle::LargeFont);
69     text_width_ = font_.GetStringWidth(text_);
70     width_ = text_width_ + kHorizontalMarginAroundText;
71     height_ = font_.GetHeight() + kVerticalMarginAroundText;
72     views::Label* label = new ExitWarningLabel;
73     label->SetText(text_);
74     label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
75     label->SetFont(font_);
76     label->SetEnabledColor(kTextColor);
77     label->SetDisabledColor(kTextColor);
78     label->SetAutoColorReadabilityEnabled(false);
79     AddChildView(label);
80     SetLayoutManager(new views::FillLayout);
81   }
82 
GetPreferredSize()83   virtual gfx::Size GetPreferredSize() OVERRIDE {
84     return gfx::Size(width_, height_);
85   }
86 
OnPaint(gfx::Canvas * canvas)87   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
88     SkPaint paint;
89     paint.setStyle(SkPaint::kFill_Style);
90     paint.setColor(kWindowBackgroundColor);
91     canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, paint);
92     views::WidgetDelegateView::OnPaint(canvas);
93   }
94 
GetAccessibleState(ui::AccessibleViewState * state)95   virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE {
96     state->name = accessible_name_;
97     state->role = ui::AccessibilityTypes::ROLE_ALERT;
98   }
99 
100  private:
101   base::string16 text_;
102   base::string16 accessible_name_;
103   gfx::Font font_;
104   int text_width_;
105   int width_;
106   int height_;
107 
108   DISALLOW_COPY_AND_ASSIGN(ExitWarningWidgetDelegateView);
109 };
110 
111 }  // namespace
112 
ExitWarningHandler()113 ExitWarningHandler::ExitWarningHandler()
114     : state_(IDLE),
115       stub_timer_for_test_(false) {
116 }
117 
~ExitWarningHandler()118 ExitWarningHandler::~ExitWarningHandler() {
119   // Note: If a timer is outstanding, it is stopped in its destructor.
120   Hide();
121 }
122 
HandleAccelerator()123 void ExitWarningHandler::HandleAccelerator() {
124   ShellDelegate* shell_delegate = Shell::GetInstance()->delegate();
125   switch (state_) {
126     case IDLE:
127       state_ = WAIT_FOR_DOUBLE_PRESS;
128       Show();
129       StartTimer();
130       Shell::GetInstance()->
131           metrics()->RecordUserMetricsAction(UMA_ACCEL_EXIT_FIRST_Q);
132       break;
133     case WAIT_FOR_DOUBLE_PRESS:
134       state_ = EXITING;
135       CancelTimer();
136       Hide();
137       Shell::GetInstance()->
138           metrics()->RecordUserMetricsAction(UMA_ACCEL_EXIT_SECOND_Q);
139       shell_delegate->Exit();
140       break;
141     case EXITING:
142       break;
143     default:
144       NOTREACHED();
145       break;
146   }
147 }
148 
TimerAction()149 void ExitWarningHandler::TimerAction() {
150   Hide();
151   if (state_ == WAIT_FOR_DOUBLE_PRESS)
152     state_ = IDLE;
153 }
154 
StartTimer()155 void ExitWarningHandler::StartTimer() {
156   if (stub_timer_for_test_)
157     return;
158   timer_.Start(FROM_HERE,
159                base::TimeDelta::FromMilliseconds(kTimeOutMilliseconds),
160                this,
161                &ExitWarningHandler::TimerAction);
162 }
163 
CancelTimer()164 void ExitWarningHandler::CancelTimer() {
165   timer_.Stop();
166 }
167 
Show()168 void ExitWarningHandler::Show() {
169   if (widget_)
170     return;
171   aura::Window* root_window = Shell::GetTargetRootWindow();
172   ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView;
173   gfx::Size rs = root_window->bounds().size();
174   gfx::Size ps = delegate->GetPreferredSize();
175   gfx::Rect bounds((rs.width() - ps.width()) / 2,
176                    (rs.height() - ps.height()) / 3,
177                    ps.width(), ps.height());
178   views::Widget::InitParams params;
179   params.type = views::Widget::InitParams::TYPE_POPUP;
180   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
181   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
182   params.accept_events = false;
183   params.can_activate = false;
184   params.keep_on_top = true;
185   params.remove_standard_frame = true;
186   params.delegate = delegate;
187   params.bounds = bounds;
188   params.parent = Shell::GetContainer(
189       root_window,
190       internal::kShellWindowId_SettingBubbleContainer);
191   widget_.reset(new views::Widget);
192   widget_->Init(params);
193   widget_->SetContentsView(delegate);
194   widget_->GetNativeView()->SetName("ExitWarningWindow");
195   widget_->Show();
196 
197   delegate->NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, true);
198 }
199 
Hide()200 void ExitWarningHandler::Hide() {
201   widget_.reset();
202 }
203 
204 }  // namespace ash
205