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
,
154 base::string16() /* title */,
155 ComposeNotificationMessage() /* message */,
156 bundle
.GetImageNamed(
157 IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT
),
158 base::string16() /* display_source */,
159 message_center::NotifierId(
160 message_center::NotifierId::SYSTEM_COMPONENT
,
161 system_notifier::kNotifierSessionLengthTimeout
),
163 NULL
/* delegate */));
164 notification
->SetSystemPriority();
165 if (message_center
->FindVisibleNotificationById(kNotificationId
))
166 message_center
->UpdateNotification(kNotificationId
, notification
.Pass());
168 message_center
->AddNotification(notification
.Pass());
169 last_limit_state_
= limit_state_
;
172 void TraySessionLengthLimit::UpdateTrayBubbleView() const {
173 if (!tray_bubble_view_
)
175 if (limit_state_
== LIMIT_NONE
)
176 tray_bubble_view_
->SetMessage(base::string16());
178 tray_bubble_view_
->SetMessage(ComposeTrayBubbleMessage());
179 tray_bubble_view_
->Layout();
182 base::string16
TraySessionLengthLimit::ComposeNotificationMessage() const {
183 return l10n_util::GetStringFUTF16(
184 IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT
,
185 ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION
,
186 ui::TimeFormat::LENGTH_LONG
,
188 remaining_session_time_
));
191 base::string16
TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
192 return l10n_util::GetStringFUTF16(
193 IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT
,
194 ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION
,
195 ui::TimeFormat::LENGTH_LONG
,
197 remaining_session_time_
));