Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ash / system / chromeos / session / tray_session_length_limit.cc
blobe4beb9094e835ce474e204a0e099ab54c8275380
1 // Copyright 2014 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.
5 #include "ash/system/chromeos/session/tray_session_length_limit.h"
7 #include <algorithm>
9 #include "ash/shell.h"
10 #include "ash/system/chromeos/label_tray_view.h"
11 #include "ash/system/system_notifier.h"
12 #include "ash/system/tray/system_tray.h"
13 #include "ash/system/tray/system_tray_delegate.h"
14 #include "ash/system/tray/system_tray_notifier.h"
15 #include "base/logging.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "grit/ash_resources.h"
18 #include "grit/ash_strings.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/l10n/time_format.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/message_center/message_center.h"
23 #include "ui/message_center/notification.h"
24 #include "ui/views/view.h"
26 namespace ash {
27 namespace {
29 // If the remaining session time falls below this threshold, the user should be
30 // informed that the session is about to expire.
31 const int kExpiringSoonThresholdInMinutes = 5;
33 // Use 500ms interval for updates to notification and tray bubble to reduce the
34 // likelihood of a user-visible skip in high load situations (as might happen
35 // with 1000ms).
36 const int kTimerIntervalInMilliseconds = 500;
38 } // namespace
40 // static
41 const char TraySessionLengthLimit::kNotificationId[] =
42 "chrome://session/timeout";
44 TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray)
45 : SystemTrayItem(system_tray),
46 limit_state_(LIMIT_NONE),
47 last_limit_state_(LIMIT_NONE),
48 tray_bubble_view_(NULL) {
49 Shell::GetInstance()->system_tray_notifier()->
50 AddSessionLengthLimitObserver(this);
51 Update();
54 TraySessionLengthLimit::~TraySessionLengthLimit() {
55 Shell::GetInstance()->system_tray_notifier()->
56 RemoveSessionLengthLimitObserver(this);
59 // Add view to tray bubble.
60 views::View* TraySessionLengthLimit::CreateDefaultView(
61 user::LoginStatus status) {
62 CHECK(!tray_bubble_view_);
63 UpdateState();
64 if (limit_state_ == LIMIT_NONE)
65 return NULL;
66 tray_bubble_view_ = new LabelTrayView(
67 NULL /* click_listener */,
68 IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT);
69 tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
70 return tray_bubble_view_;
73 // View has been removed from tray bubble.
74 void TraySessionLengthLimit::DestroyDefaultView() {
75 tray_bubble_view_ = NULL;
78 void TraySessionLengthLimit::OnSessionStartTimeChanged() {
79 Update();
82 void TraySessionLengthLimit::OnSessionLengthLimitChanged() {
83 Update();
86 void TraySessionLengthLimit::Update() {
87 UpdateState();
88 UpdateNotification();
89 UpdateTrayBubbleView();
92 void TraySessionLengthLimit::UpdateState() {
93 SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
94 if (delegate->GetSessionStartTime(&session_start_time_) &&
95 delegate->GetSessionLengthLimit(&time_limit_)) {
96 const base::TimeDelta expiring_soon_threshold(
97 base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes));
98 remaining_session_time_ = std::max(
99 time_limit_ - (base::TimeTicks::Now() - session_start_time_),
100 base::TimeDelta());
101 limit_state_ = remaining_session_time_ <= expiring_soon_threshold ?
102 LIMIT_EXPIRING_SOON : LIMIT_SET;
103 if (!timer_)
104 timer_.reset(new base::RepeatingTimer<TraySessionLengthLimit>);
105 if (!timer_->IsRunning()) {
106 timer_->Start(FROM_HERE,
107 base::TimeDelta::FromMilliseconds(
108 kTimerIntervalInMilliseconds),
109 this,
110 &TraySessionLengthLimit::Update);
112 } else {
113 remaining_session_time_ = base::TimeDelta();
114 limit_state_ = LIMIT_NONE;
115 timer_.reset();
119 void TraySessionLengthLimit::UpdateNotification() {
120 message_center::MessageCenter* message_center =
121 message_center::MessageCenter::Get();
123 // If state hasn't changed and the notification has already been acknowledged,
124 // we won't re-create it.
125 if (limit_state_ == last_limit_state_ &&
126 !message_center->FindVisibleNotificationById(kNotificationId)) {
127 return;
130 // After state change, any possibly existing notification is removed to make
131 // sure it is re-shown even if it had been acknowledged by the user before
132 // (and in the rare case of state change towards LIMIT_NONE to make the
133 // notification disappear).
134 if (limit_state_ != last_limit_state_ &&
135 message_center->FindVisibleNotificationById(kNotificationId)) {
136 message_center::MessageCenter::Get()->RemoveNotification(
137 kNotificationId, false /* by_user */);
140 // For LIMIT_NONE, there's nothing more to do.
141 if (limit_state_ == LIMIT_NONE) {
142 last_limit_state_ = limit_state_;
143 return;
146 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
147 message_center::RichNotificationData data;
148 data.should_make_spoken_feedback_for_popup_updates =
149 (limit_state_ != last_limit_state_);
150 scoped_ptr<message_center::Notification> notification(
151 new message_center::Notification(
152 message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
153 base::string16() /* title */,
154 ComposeNotificationMessage() /* message */,
155 bundle.GetImageNamed(
156 IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT),
157 base::string16() /* display_source */, GURL(),
158 message_center::NotifierId(
159 message_center::NotifierId::SYSTEM_COMPONENT,
160 system_notifier::kNotifierSessionLengthTimeout),
161 data, NULL /* delegate */));
162 notification->SetSystemPriority();
163 if (message_center->FindVisibleNotificationById(kNotificationId))
164 message_center->UpdateNotification(kNotificationId, notification.Pass());
165 else
166 message_center->AddNotification(notification.Pass());
167 last_limit_state_ = limit_state_;
170 void TraySessionLengthLimit::UpdateTrayBubbleView() const {
171 if (!tray_bubble_view_)
172 return;
173 if (limit_state_ == LIMIT_NONE)
174 tray_bubble_view_->SetMessage(base::string16());
175 else
176 tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
177 tray_bubble_view_->Layout();
180 base::string16 TraySessionLengthLimit::ComposeNotificationMessage() const {
181 return l10n_util::GetStringFUTF16(
182 IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT,
183 ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
184 ui::TimeFormat::LENGTH_LONG,
186 remaining_session_time_));
189 base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
190 return l10n_util::GetStringFUTF16(
191 IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT,
192 ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
193 ui::TimeFormat::LENGTH_LONG,
195 remaining_session_time_));
198 } // namespace ash