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