tray_session_length_limit.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/system/chromeos/session/tray_session_length_limit.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ash/system/chromeos/label_tray_view.h"
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/system/system_notifier.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/tray/system_tray.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/system/tray/system_tray_notifier.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ash_resources.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ash_strings.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/base/l10n/time_format.h"
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/message_center/message_center.h"
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/message_center/notification.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/view.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace ash {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// If the remaining session time falls below this threshold, the user should be
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// informed that the session is about to expire.
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kExpiringSoonThresholdInMinutes = 5;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use 500ms interval for updates to notification and tray bubble to reduce the
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// likelihood of a user-visible skip in high load situations (as might happen
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// with 1000ms).
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kTimerIntervalInMilliseconds = 500;
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char TraySessionLengthLimit::kNotificationId[] =
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "chrome://session/timeout";
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : SystemTrayItem(system_tray),
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      limit_state_(LIMIT_NONE),
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      last_limit_state_(LIMIT_NONE),
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      tray_bubble_view_(NULL) {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Shell::GetInstance()->system_tray_notifier()->
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AddSessionLengthLimitObserver(this);
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Update();
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TraySessionLengthLimit::~TraySessionLengthLimit() {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Shell::GetInstance()->system_tray_notifier()->
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RemoveSessionLengthLimitObserver(this);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Add view to tray bubble.
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)views::View* TraySessionLengthLimit::CreateDefaultView(
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    user::LoginStatus status) {
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(!tray_bubble_view_);
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateState();
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (limit_state_ == LIMIT_NONE)
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NULL;
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  tray_bubble_view_ = new LabelTrayView(
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NULL /* click_listener */,
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT);
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return tray_bubble_view_;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// View has been removed from tray bubble.
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TraySessionLengthLimit::DestroyDefaultView() {
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  tray_bubble_view_ = NULL;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TraySessionLengthLimit::OnSessionStartTimeChanged() {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Update();
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TraySessionLengthLimit::OnSessionLengthLimitChanged() {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Update();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TraySessionLengthLimit::Update() {
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateState();
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateNotification();
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UpdateTrayBubbleView();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TraySessionLengthLimit::UpdateState() {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (delegate->GetSessionStartTime(&session_start_time_) &&
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      delegate->GetSessionLengthLimit(&time_limit_)) {
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::TimeDelta expiring_soon_threshold(
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes));
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    remaining_session_time_ = std::max(
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        time_limit_ - (base::TimeTicks::Now() - session_start_time_),
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta());
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    limit_state_ = remaining_session_time_ <= expiring_soon_threshold ?
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        LIMIT_EXPIRING_SOON : LIMIT_SET;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!timer_)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      timer_.reset(new base::RepeatingTimer<TraySessionLengthLimit>);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!timer_->IsRunning()) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      timer_->Start(FROM_HERE,
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                    base::TimeDelta::FromMilliseconds(
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        kTimerIntervalInMilliseconds),
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    this,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    &TraySessionLengthLimit::Update);
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    remaining_session_time_ = base::TimeDelta();
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    limit_state_ = LIMIT_NONE;
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    timer_.reset();
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TraySessionLengthLimit::UpdateNotification() {
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message_center::MessageCenter* message_center =
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      message_center::MessageCenter::Get();
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // If state hasn't changed and the notification has already been acknowledged,
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // we won't re-create it.
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (limit_state_ == last_limit_state_ &&
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      !message_center->FindVisibleNotificationById(kNotificationId)) {
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // After state change, any possibly existing notification is removed to make
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // sure it is re-shown even if it had been acknowledged by the user before
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // (and in the rare case of state change towards LIMIT_NONE to make the
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // notification disappear).
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (limit_state_ != last_limit_state_ &&
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      message_center->FindVisibleNotificationById(kNotificationId)) {
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    message_center::MessageCenter::Get()->RemoveNotification(
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        kNotificationId, false /* by_user */);
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // For LIMIT_NONE, there's nothing more to do.
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (limit_state_ == LIMIT_NONE) {
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    last_limit_state_ = limit_state_;
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message_center::RichNotificationData data;
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  data.should_make_spoken_feedback_for_popup_updates =
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (limit_state_ != last_limit_state_);
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<message_center::Notification> notification(
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new message_center::Notification(
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          message_center::NOTIFICATION_TYPE_SIMPLE,
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          kNotificationId,
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::string16() /* title */,
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ComposeNotificationMessage() /* message */,
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          bundle.GetImageNamed(
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT),
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::string16() /* display_source */,
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          message_center::NotifierId(
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              message_center::NotifierId::SYSTEM_COMPONENT,
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              system_notifier::kNotifierSessionLengthTimeout),
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          data,
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          NULL /* delegate */));
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  notification->SetSystemPriority();
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (message_center->FindVisibleNotificationById(kNotificationId))
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    message_center->UpdateNotification(kNotificationId, notification.Pass());
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    message_center->AddNotification(notification.Pass());
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  last_limit_state_ = limit_state_;
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void TraySessionLengthLimit::UpdateTrayBubbleView() const {
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!tray_bubble_view_)
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (limit_state_ == LIMIT_NONE)
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    tray_bubble_view_->SetMessage(base::string16());
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  tray_bubble_view_->Layout();
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::string16 TraySessionLengthLimit::ComposeNotificationMessage() const {
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return l10n_util::GetStringFUTF16(
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT,
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               ui::TimeFormat::LENGTH_LONG,
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               10,
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               remaining_session_time_));
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return l10n_util::GetStringFUTF16(
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT,
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               ui::TimeFormat::LENGTH_LONG,
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               10,
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               remaining_session_time_));
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace ash
201