1// Copyright (c) 2012 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 "chrome/browser/chromeos/ui/idle_logout_dialog_view.h"
6
7#include "ash/shell.h"
8#include "base/bind.h"
9#include "base/bind_helpers.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/time/time.h"
13#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
14#include "chrome/browser/ui/browser_list.h"
15#include "chrome/grit/generated_resources.h"
16#include "chromeos/dbus/dbus_thread_manager.h"
17#include "chromeos/dbus/session_manager_client.h"
18#include "ui/aura/window_event_dispatcher.h"
19#include "ui/base/l10n/l10n_util.h"
20#include "ui/views/controls/label.h"
21#include "ui/views/layout/grid_layout.h"
22#include "ui/views/layout/layout_constants.h"
23#include "ui/views/widget/widget.h"
24
25namespace {
26
27// Global singleton instance of our dialog class.
28chromeos::IdleLogoutDialogView* g_instance = NULL;
29
30const int kIdleLogoutDialogMaxWidth = 300;
31const int kCountdownUpdateIntervalMs = 1000;
32
33}  // namespace
34
35namespace chromeos {
36
37IdleLogoutSettingsProvider* IdleLogoutDialogView::provider_ = NULL;
38
39////////////////////////////////////////////////////////////////////////////////
40// IdleLogoutSettingsProvider public methods
41IdleLogoutSettingsProvider::IdleLogoutSettingsProvider() {
42}
43
44IdleLogoutSettingsProvider::~IdleLogoutSettingsProvider() {
45}
46
47base::TimeDelta IdleLogoutSettingsProvider::GetCountdownUpdateInterval() {
48  return base::TimeDelta::FromMilliseconds(kCountdownUpdateIntervalMs);
49}
50
51KioskModeSettings* IdleLogoutSettingsProvider::GetKioskModeSettings() {
52  return KioskModeSettings::Get();
53}
54
55void IdleLogoutSettingsProvider::LogoutCurrentUser(IdleLogoutDialogView*) {
56  DBusThreadManager::Get()->GetSessionManagerClient()->StopSession();
57}
58
59////////////////////////////////////////////////////////////////////////////////
60// IdleLogoutDialogView public static methods
61// static
62void IdleLogoutDialogView::ShowDialog() {
63  // We only show the dialog if it is not already showing. We don't want two
64  // countdowns on the screen for any reason. If the dialog is closed by using
65  // CloseDialog, we reset g_instance so the next Show will work correctly; in
66  // case the dialog is closed by the system, DeleteDelegate is guaranteed to be
67  // called, in which case we reset g_instance there if not already reset.
68  if (!g_instance) {
69    g_instance = new IdleLogoutDialogView();
70    g_instance->InitAndShow();
71  }
72}
73
74// static
75void IdleLogoutDialogView::CloseDialog() {
76  if (g_instance)
77    g_instance->GetWidget()->Close();
78}
79
80////////////////////////////////////////////////////////////////////////////////
81// Overridden from views::DialogDelegateView
82int IdleLogoutDialogView::GetDialogButtons() const {
83  return ui::DIALOG_BUTTON_NONE;
84}
85
86ui::ModalType IdleLogoutDialogView::GetModalType() const {
87  return ui::MODAL_TYPE_WINDOW;
88}
89
90base::string16 IdleLogoutDialogView::GetWindowTitle() const {
91  return l10n_util::GetStringUTF16(IDS_IDLE_LOGOUT_TITLE);
92}
93
94bool IdleLogoutDialogView::Close() {
95  if (timer_.IsRunning())
96    timer_.Stop();
97
98  // We just closed our dialog. The global
99  // instance is invalid now, set it to null.
100  g_instance = NULL;
101
102  return true;
103}
104
105////////////////////////////////////////////////////////////////////////////////
106// IdleLogoutDialog private methods
107IdleLogoutDialogView::IdleLogoutDialogView()
108    : restart_label_(NULL),
109      weak_ptr_factory_(this) {
110  if (!IdleLogoutDialogView::provider_)
111    IdleLogoutDialogView::provider_ = new IdleLogoutSettingsProvider();
112}
113
114IdleLogoutDialogView::~IdleLogoutDialogView() {
115  if (this == g_instance)
116    g_instance = NULL;
117}
118
119void IdleLogoutDialogView::InitAndShow() {
120  KioskModeSettings* settings =
121      IdleLogoutDialogView::provider_->GetKioskModeSettings();
122  if (!settings->is_initialized()) {
123    settings->Initialize(base::Bind(&IdleLogoutDialogView::InitAndShow,
124                                    weak_ptr_factory_.GetWeakPtr()));
125    return;
126  }
127
128  restart_label_ = new views::Label();
129  restart_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
130  restart_label_->SetMultiLine(true);
131
132  views::GridLayout* layout = views::GridLayout::CreatePanel(this);
133  SetLayoutManager(layout);
134
135  views::ColumnSet* column_set = layout->AddColumnSet(0);
136  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 1,
137                        views::GridLayout::FIXED, kIdleLogoutDialogMaxWidth, 0);
138  layout->StartRow(0, 0);
139  layout->AddPaddingRow(0, views::kRelatedControlHorizontalSpacing);
140  layout->StartRow(0, 0);
141  layout->AddView(restart_label_);
142  layout->AddPaddingRow(0, views::kRelatedControlHorizontalSpacing);
143
144  // We're initialized, show the dialog.
145  Show();
146}
147
148void IdleLogoutDialogView::Show() {
149  KioskModeSettings* settings =
150        IdleLogoutDialogView::provider_->GetKioskModeSettings();
151
152  // Setup the countdown label before showing.
153  countdown_end_time_ = base::Time::Now() +
154      settings->GetIdleLogoutWarningDuration();
155
156  UpdateCountdown();
157
158  views::DialogDelegate::CreateDialogWidget(
159      this, ash::Shell::GetPrimaryRootWindow(), NULL);
160  GetWidget()->SetAlwaysOnTop(true);
161  GetWidget()->Show();
162
163  // Update countdown every 1 second.
164  timer_.Start(FROM_HERE,
165               IdleLogoutDialogView::provider_->GetCountdownUpdateInterval(),
166               this,
167               &IdleLogoutDialogView::UpdateCountdown);
168}
169
170void IdleLogoutDialogView::UpdateCountdown() {
171  base::TimeDelta logout_warning_time = countdown_end_time_ -
172                                        base::Time::Now();
173  int64 seconds_left = (logout_warning_time.InMillisecondsF() /
174                        base::Time::kMillisecondsPerSecond) + 0.5;
175
176  if (seconds_left > 1) {
177    restart_label_->SetText(l10n_util::GetStringFUTF16(
178        IDS_IDLE_LOGOUT_WARNING_RESTART,
179        base::Int64ToString16(seconds_left)));
180  } else if (seconds_left > 0) {
181    restart_label_->SetText(l10n_util::GetStringUTF16(
182        IDS_IDLE_LOGOUT_WARNING_RESTART_1S));
183  } else {
184    // Set the label - the logout probably won't be instant.
185    restart_label_->SetText(l10n_util::GetStringUTF16(
186        IDS_IDLE_LOGOUT_WARNING_RESTART_NOW));
187
188    // We're done; stop the timer and logout.
189    timer_.Stop();
190    IdleLogoutDialogView::provider_->LogoutCurrentUser(this);
191  }
192}
193
194// static
195IdleLogoutDialogView* IdleLogoutDialogView::current_instance() {
196  return g_instance;
197}
198
199// static
200void IdleLogoutDialogView::set_settings_provider(
201    IdleLogoutSettingsProvider* provider) {
202  provider_ = provider;
203}
204
205}  // namespace chromeos
206