190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/accelerators/exit_warning_handler.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/metrics/user_metrics_recorder.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/shell.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/shell_delegate.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ash/shell_window_ids.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "grit/ash_strings.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/aura/window.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/gfx/canvas.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/font_list.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/text_utils.h"
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/controls/label.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/layout/fill_layout.h"
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/view.h"
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/widget/widget.h"
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/views/widget/widget_delegate.h"
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace ash {
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int64 kTimeOutMilliseconds = 2000;
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Color of the text of the warning message.
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const SkColor kTextColor = SK_ColorWHITE;
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Color of the window background.
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0);
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Radius of the rounded corners of the window.
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kWindowCornerRadius = 2;
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kHorizontalMarginAroundText = 100;
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kVerticalMarginAroundText = 100;
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class ExitWarningWidgetDelegateView : public views::WidgetDelegateView {
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExitWarningWidgetDelegateView() : text_width_(0), width_(0), height_(0) {
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#ifdef OS_CHROMEOS
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    text_ = l10n_util::GetStringUTF16(IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT);
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    accessible_name_ = l10n_util::GetStringUTF16(
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT_ACCESSIBLE);
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#else
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    text_ = l10n_util::GetStringUTF16(IDS_ASH_EXIT_WARNING_POPUP_TEXT);
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    accessible_name_ =
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        l10n_util::GetStringUTF16(IDS_ASH_EXIT_WARNING_POPUP_TEXT_ACCESSIBLE);
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::FontList& font_list =
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        rb.GetFontList(ui::ResourceBundle::LargeFont);
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    text_width_ = gfx::GetStringWidth(text_, font_list);
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    width_ = text_width_ + kHorizontalMarginAroundText;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    height_ = font_list.GetHeight() + kVerticalMarginAroundText;
596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    views::Label* label = new views::Label();
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    label->SetText(text_);
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    label->SetFontList(font_list);
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    label->SetEnabledColor(kTextColor);
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    label->SetDisabledColor(kTextColor);
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    label->SetAutoColorReadabilityEnabled(false);
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    label->SetSubpixelRenderingEnabled(false);
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    AddChildView(label);
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SetLayoutManager(new views::FillLayout);
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual gfx::Size GetPreferredSize() const OVERRIDE {
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return gfx::Size(width_, height_);
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SkPaint paint;
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    paint.setStyle(SkPaint::kFill_Style);
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    paint.setColor(kWindowBackgroundColor);
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, paint);
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    views::WidgetDelegateView::OnPaint(canvas);
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE {
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    state->name = accessible_name_;
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    state->role = ui::AX_ROLE_ALERT;
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::string16 text_;
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::string16 accessible_name_;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int text_width_;
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int width_;
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int height_;
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ExitWarningWidgetDelegateView);
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ExitWarningHandler::ExitWarningHandler()
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : state_(IDLE),
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      stub_timer_for_test_(false) {
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ExitWarningHandler::~ExitWarningHandler() {
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Note: If a timer is outstanding, it is stopped in its destructor.
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Hide();
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::HandleAccelerator() {
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ShellDelegate* shell_delegate = Shell::GetInstance()->delegate();
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (state_) {
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case IDLE:
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      state_ = WAIT_FOR_DOUBLE_PRESS;
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      Show();
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      StartTimer();
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Shell::GetInstance()->
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          metrics()->RecordUserMetricsAction(UMA_ACCEL_EXIT_FIRST_Q);
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case WAIT_FOR_DOUBLE_PRESS:
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      state_ = EXITING;
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CancelTimer();
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      Hide();
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Shell::GetInstance()->
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          metrics()->RecordUserMetricsAction(UMA_ACCEL_EXIT_SECOND_Q);
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      shell_delegate->Exit();
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case EXITING:
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    default:
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NOTREACHED();
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::TimerAction() {
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Hide();
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state_ == WAIT_FOR_DOUBLE_PRESS)
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    state_ = IDLE;
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::StartTimer() {
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (stub_timer_for_test_)
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  timer_.Start(FROM_HERE,
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               base::TimeDelta::FromMilliseconds(kTimeOutMilliseconds),
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               this,
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               &ExitWarningHandler::TimerAction);
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::CancelTimer() {
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  timer_.Stop();
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::Show() {
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (widget_)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::Window* root_window = Shell::GetTargetRootWindow();
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView;
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::Size rs = root_window->bounds().size();
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::Size ps = delegate->GetPreferredSize();
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::Rect bounds((rs.width() - ps.width()) / 2,
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   (rs.height() - ps.height()) / 3,
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   ps.width(), ps.height());
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  views::Widget::InitParams params;
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.type = views::Widget::InitParams::TYPE_POPUP;
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.accept_events = false;
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.keep_on_top = true;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.remove_standard_frame = true;
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.delegate = delegate;
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params.bounds = bounds;
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  params.parent =
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      Shell::GetContainer(root_window, kShellWindowId_SettingBubbleContainer);
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  widget_.reset(new views::Widget);
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  widget_->Init(params);
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  widget_->SetContentsView(delegate);
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  widget_->GetNativeView()->SetName("ExitWarningWindow");
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  widget_->Show();
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delegate->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExitWarningHandler::Hide() {
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  widget_.reset();
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace ash
190