Home | History | Annotate | Download | only in accelerators
      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:
     42   ExitWarningLabel() {}
     43 
     44   virtual ~ExitWarningLabel() {}
     45 
     46  private:
     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:
     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 
     83   virtual gfx::Size GetPreferredSize() OVERRIDE {
     84     return gfx::Size(width_, height_);
     85   }
     86 
     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 
     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 
    113 ExitWarningHandler::ExitWarningHandler()
    114     : state_(IDLE),
    115       stub_timer_for_test_(false) {
    116 }
    117 
    118 ExitWarningHandler::~ExitWarningHandler() {
    119   // Note: If a timer is outstanding, it is stopped in its destructor.
    120   Hide();
    121 }
    122 
    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 
    149 void ExitWarningHandler::TimerAction() {
    150   Hide();
    151   if (state_ == WAIT_FOR_DOUBLE_PRESS)
    152     state_ = IDLE;
    153 }
    154 
    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 
    164 void ExitWarningHandler::CancelTimer() {
    165   timer_.Stop();
    166 }
    167 
    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 
    200 void ExitWarningHandler::Hide() {
    201   widget_.reset();
    202 }
    203 
    204 }  // namespace ash
    205