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"
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"
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
36 const int kTimerIntervalInMilliseconds
= 500;
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);
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_
);
64 if (limit_state_
== LIMIT_NONE
)
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() {
82 void TraySessionLengthLimit::OnSessionLengthLimitChanged() {
86 void TraySessionLengthLimit::Update() {
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_
),
101 limit_state_
= remaining_session_time_
<= expiring_soon_threshold
?
102 LIMIT_EXPIRING_SOON
: LIMIT_SET
;
104 timer_
.reset(new base::RepeatingTimer
<TraySessionLengthLimit
>);
105 if (!timer_
->IsRunning()) {
106 timer_
->Start(FROM_HERE
,
107 base::TimeDelta::FromMilliseconds(
108 kTimerIntervalInMilliseconds
),
110 &TraySessionLengthLimit::Update
);
113 remaining_session_time_
= base::TimeDelta();
114 limit_state_
= LIMIT_NONE
;
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
)) {
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_
;
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());
166 message_center
->AddNotification(notification
.Pass());
167 last_limit_state_
= limit_state_
;
170 void TraySessionLengthLimit::UpdateTrayBubbleView() const {
171 if (!tray_bubble_view_
)
173 if (limit_state_
== LIMIT_NONE
)
174 tray_bubble_view_
->SetMessage(base::string16());
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_
));