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