Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9347)

Unified Diff: ash/system/chromeos/session/tray_session_length_limit.cc

Issue 262973004: Move session length timer into tray bubble. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ash/system/chromeos/session/tray_session_length_limit.cc
diff --git a/ash/system/chromeos/session/tray_session_length_limit.cc b/ash/system/chromeos/session/tray_session_length_limit.cc
index 6e1df7a57fb1df9d6b1b759e06d911ddb8e38782..6666c021c3b61d0a8ebbed1ebdd8c8d8d6b97d55 100644
--- a/ash/system/chromeos/session/tray_session_length_limit.cc
+++ b/ash/system/chromeos/session/tray_session_length_limit.cc
@@ -6,287 +6,46 @@
#include <algorithm>
-#include "ash/shelf/shelf_types.h"
#include "ash/shell.h"
+#include "ash/system/chromeos/label_tray_view.h"
#include "ash/system/system_notifier.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_notifier.h"
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/tray/tray_utils.h"
-#include "base/location.h"
#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
-#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font_list.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
-using message_center::Notification;
-
namespace ash {
namespace {
// If the remaining session time falls below this threshold, the user should be
// informed that the session is about to expire.
-const int kExpiringSoonThresholdInSeconds = 5 * 60; // 5 minutes.
-
-// Color in which the remaining session time is normally shown.
-const SkColor kRemainingTimeColor = SK_ColorWHITE;
-// Color in which the remaining session time is shown when it is expiring soon.
-const SkColor kRemainingTimeExpiringSoonColor = SK_ColorRED;
+const int kExpiringSoonThresholdInMinutes = 5;
-views::Label* CreateAndSetupLabel() {
- views::Label* label = new views::Label;
- label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
- SetupLabelForTray(label);
- label->SetFontList(label->font_list().DeriveWithStyle(
- label->font_list().GetFontStyle() & ~gfx::Font::BOLD));
- return label;
-}
-
-base::string16 IntToTwoDigitString(int value) {
- DCHECK_GE(value, 0);
- DCHECK_LE(value, 99);
- if (value < 10)
- return base::ASCIIToUTF16("0") + base::IntToString16(value);
- return base::IntToString16(value);
-}
-
-base::string16 FormatRemainingSessionTimeNotification(
- const base::TimeDelta& remaining_session_time) {
- return l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_REMAINING_SESSION_TIME_NOTIFICATION,
- ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
- ui::TimeFormat::LENGTH_LONG,
- 10,
- remaining_session_time));
-}
-
-// Creates, or updates the notification for session length timeout with
-// |remaining_time|. |state_changed| is true when its internal state has been
-// changed from another.
-void CreateOrUpdateNotification(const std::string& notification_id,
- const base::TimeDelta& remaining_time,
- bool state_changed) {
- message_center::MessageCenter* message_center =
- message_center::MessageCenter::Get();
-
- // Do not create a new notification if no state has changed. It may happen
- // when the notification is already closed by the user, see crbug.com/285941.
- if (!state_changed && !message_center->HasNotification(notification_id))
- return;
-
- ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
- message_center::RichNotificationData data;
- // Makes the spoken feedback only when the state has been changed.
- data.should_make_spoken_feedback_for_popup_updates = state_changed;
- scoped_ptr<Notification> notification(new Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE,
- notification_id,
- FormatRemainingSessionTimeNotification(remaining_time),
- base::string16() /* message */,
- bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SESSION_LENGTH_LIMIT_TIMER),
- base::string16() /* display_source */,
- message_center::NotifierId(
- message_center::NotifierId::SYSTEM_COMPONENT,
- system_notifier::kNotifierSessionLengthTimeout),
- data,
- NULL /* delegate */));
- notification->SetSystemPriority();
- message_center::MessageCenter::Get()->AddNotification(notification.Pass());
-}
+// Use 500ms interval for updates to notification and tray bubble to reduce the
+// likelihood of a user-visible skip in high load situations (as might happen
+// with 1000ms).
+const int kTimerIntervalInMilliseconds = 500;
} // namespace
-namespace tray {
-
-class RemainingSessionTimeTrayView : public views::View {
- public:
- RemainingSessionTimeTrayView(const TraySessionLengthLimit* owner,
- ShelfAlignment shelf_alignment);
- virtual ~RemainingSessionTimeTrayView();
-
- void UpdateClockLayout(ShelfAlignment shelf_alignment);
- void Update();
-
- private:
- void SetBorderFromAlignment(ShelfAlignment shelf_alignment);
-
- const TraySessionLengthLimit* owner_;
-
- views::Label* horizontal_layout_label_;
- views::Label* vertical_layout_label_hours_left_;
- views::Label* vertical_layout_label_hours_right_;
- views::Label* vertical_layout_label_minutes_left_;
- views::Label* vertical_layout_label_minutes_right_;
- views::Label* vertical_layout_label_seconds_left_;
- views::Label* vertical_layout_label_seconds_right_;
-
- DISALLOW_COPY_AND_ASSIGN(RemainingSessionTimeTrayView);
-};
-
-RemainingSessionTimeTrayView::RemainingSessionTimeTrayView(
- const TraySessionLengthLimit* owner,
- ShelfAlignment shelf_alignment)
- : owner_(owner),
- horizontal_layout_label_(NULL),
- vertical_layout_label_hours_left_(NULL),
- vertical_layout_label_hours_right_(NULL),
- vertical_layout_label_minutes_left_(NULL),
- vertical_layout_label_minutes_right_(NULL),
- vertical_layout_label_seconds_left_(NULL),
- vertical_layout_label_seconds_right_(NULL) {
- UpdateClockLayout(shelf_alignment);
-}
-
-RemainingSessionTimeTrayView::~RemainingSessionTimeTrayView() {
-}
-
-void RemainingSessionTimeTrayView::UpdateClockLayout(
- ShelfAlignment shelf_alignment) {
- SetBorderFromAlignment(shelf_alignment);
- const bool horizontal_layout = (shelf_alignment == SHELF_ALIGNMENT_BOTTOM ||
- shelf_alignment == SHELF_ALIGNMENT_TOP);
- if (horizontal_layout && !horizontal_layout_label_) {
- // Remove labels used for vertical layout.
- RemoveAllChildViews(true);
- vertical_layout_label_hours_left_ = NULL;
- vertical_layout_label_hours_right_ = NULL;
- vertical_layout_label_minutes_left_ = NULL;
- vertical_layout_label_minutes_right_ = NULL;
- vertical_layout_label_seconds_left_ = NULL;
- vertical_layout_label_seconds_right_ = NULL;
-
- // Create label used for horizontal layout.
- horizontal_layout_label_ = CreateAndSetupLabel();
-
- // Construct layout.
- SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
- AddChildView(horizontal_layout_label_);
-
- } else if (!horizontal_layout && horizontal_layout_label_) {
- // Remove label used for horizontal layout.
- RemoveAllChildViews(true);
- horizontal_layout_label_ = NULL;
-
- // Create labels used for vertical layout.
- vertical_layout_label_hours_left_ = CreateAndSetupLabel();
- vertical_layout_label_hours_right_ = CreateAndSetupLabel();
- vertical_layout_label_minutes_left_ = CreateAndSetupLabel();
- vertical_layout_label_minutes_right_ = CreateAndSetupLabel();
- vertical_layout_label_seconds_left_ = CreateAndSetupLabel();
- vertical_layout_label_seconds_right_ = CreateAndSetupLabel();
-
- // Construct layout.
- views::GridLayout* layout = new views::GridLayout(this);
- SetLayoutManager(layout);
- views::ColumnSet* columns = layout->AddColumnSet(0);
- columns->AddPaddingColumn(0, 6);
- columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
- 0, views::GridLayout::USE_PREF, 0, 0);
- columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER,
- 0, views::GridLayout::USE_PREF, 0, 0);
- layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
- layout->StartRow(0, 0);
- layout->AddView(vertical_layout_label_hours_left_);
- layout->AddView(vertical_layout_label_hours_right_);
- layout->StartRow(0, 0);
- layout->AddView(vertical_layout_label_minutes_left_);
- layout->AddView(vertical_layout_label_minutes_right_);
- layout->StartRow(0, 0);
- layout->AddView(vertical_layout_label_seconds_left_);
- layout->AddView(vertical_layout_label_seconds_right_);
- layout->AddPaddingRow(0, kTrayLabelItemVerticalPaddingVerticalAlignment);
- }
- Update();
-}
-
-void RemainingSessionTimeTrayView::Update() {
- const TraySessionLengthLimit::LimitState limit_state =
- owner_->GetLimitState();
-
- if (limit_state == TraySessionLengthLimit::LIMIT_NONE) {
- SetVisible(false);
- return;
- }
-
- int seconds = owner_->GetRemainingSessionTime().InSeconds();
- // If the remaining session time is 100 hours or more, show 99:59:59 instead.
- seconds = std::min(seconds, 100 * 60 * 60 - 1); // 100 hours - 1 second.
- int minutes = seconds / 60;
- seconds %= 60;
- const int hours = minutes / 60;
- minutes %= 60;
-
- const base::string16 hours_str = IntToTwoDigitString(hours);
- const base::string16 minutes_str = IntToTwoDigitString(minutes);
- const base::string16 seconds_str = IntToTwoDigitString(seconds);
- const SkColor color =
- limit_state == TraySessionLengthLimit::LIMIT_EXPIRING_SOON ?
- kRemainingTimeExpiringSoonColor : kRemainingTimeColor;
-
- if (horizontal_layout_label_) {
- horizontal_layout_label_->SetText(l10n_util::GetStringFUTF16(
- IDS_ASH_STATUS_TRAY_REMAINING_SESSION_TIME,
- hours_str, minutes_str, seconds_str));
- horizontal_layout_label_->SetEnabledColor(color);
- } else if (vertical_layout_label_hours_left_) {
- vertical_layout_label_hours_left_->SetText(hours_str.substr(0, 1));
- vertical_layout_label_hours_right_->SetText(hours_str.substr(1, 1));
- vertical_layout_label_minutes_left_->SetText(minutes_str.substr(0, 1));
- vertical_layout_label_minutes_right_->SetText(minutes_str.substr(1, 1));
- vertical_layout_label_seconds_left_->SetText(seconds_str.substr(0, 1));
- vertical_layout_label_seconds_right_->SetText(seconds_str.substr(1, 1));
- vertical_layout_label_hours_left_->SetEnabledColor(color);
- vertical_layout_label_hours_right_->SetEnabledColor(color);
- vertical_layout_label_minutes_left_->SetEnabledColor(color);
- vertical_layout_label_minutes_right_->SetEnabledColor(color);
- vertical_layout_label_seconds_left_->SetEnabledColor(color);
- vertical_layout_label_seconds_right_->SetEnabledColor(color);
- }
-
- Layout();
- SetVisible(true);
-}
-
-void RemainingSessionTimeTrayView::SetBorderFromAlignment(
- ShelfAlignment shelf_alignment) {
- if (shelf_alignment == SHELF_ALIGNMENT_BOTTOM ||
- shelf_alignment == SHELF_ALIGNMENT_TOP) {
- SetBorder(views::Border::CreateEmptyBorder(
- 0,
- kTrayLabelItemHorizontalPaddingBottomAlignment,
- 0,
- kTrayLabelItemHorizontalPaddingBottomAlignment));
- } else {
- SetBorder(views::Border::NullBorder());
- }
-}
-
-} // namespace tray
-
// static
const char TraySessionLengthLimit::kNotificationId[] =
"chrome://session/timeout";
TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray)
: SystemTrayItem(system_tray),
- tray_view_(NULL),
- limit_state_(LIMIT_NONE) {
+ limit_state_(LIMIT_NONE),
+ last_limit_state_(LIMIT_NONE),
+ tray_bubble_view_(NULL) {
Shell::GetInstance()->system_tray_notifier()->
AddSessionLengthLimitObserver(this);
Update();
@@ -297,21 +56,23 @@ TraySessionLengthLimit::~TraySessionLengthLimit() {
RemoveSessionLengthLimitObserver(this);
}
-views::View* TraySessionLengthLimit::CreateTrayView(user::LoginStatus status) {
- CHECK(tray_view_ == NULL);
- tray_view_ = new tray::RemainingSessionTimeTrayView(
- this, system_tray()->shelf_alignment());
- return tray_view_;
+// Add view to tray bubble.
+views::View* TraySessionLengthLimit::CreateDefaultView(
+ user::LoginStatus status) {
+ CHECK(!tray_bubble_view_);
+ UpdateState();
+ if (limit_state_ == LIMIT_NONE)
+ return NULL;
+ tray_bubble_view_ = new LabelTrayView(
+ NULL /* click_listener */,
+ IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT);
+ tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
+ return tray_bubble_view_;
}
-void TraySessionLengthLimit::DestroyTrayView() {
- tray_view_ = NULL;
-}
-
-void TraySessionLengthLimit::UpdateAfterShelfAlignmentChange(
- ShelfAlignment alignment) {
- if (tray_view_)
- tray_view_->UpdateClockLayout(alignment);
+// View has been removed from tray bubble.
+void TraySessionLengthLimit::DestroyDefaultView() {
+ tray_bubble_view_ = NULL;
}
void TraySessionLengthLimit::OnSessionStartTimeChanged() {
@@ -322,68 +83,118 @@ void TraySessionLengthLimit::OnSessionLengthLimitChanged() {
Update();
}
-TraySessionLengthLimit::LimitState
- TraySessionLengthLimit::GetLimitState() const {
- return limit_state_;
-}
-
-base::TimeDelta TraySessionLengthLimit::GetRemainingSessionTime() const {
- return remaining_session_time_;
+void TraySessionLengthLimit::Update() {
+ UpdateState();
+ UpdateNotification();
+ UpdateTrayBubbleView();
}
-void TraySessionLengthLimit::Update() {
+void TraySessionLengthLimit::UpdateState() {
SystemTrayDelegate* delegate = Shell::GetInstance()->system_tray_delegate();
- const LimitState previous_limit_state = limit_state_;
- if (!delegate->GetSessionStartTime(&session_start_time_) ||
- !delegate->GetSessionLengthLimit(&limit_)) {
- remaining_session_time_ = base::TimeDelta();
- limit_state_ = LIMIT_NONE;
- timer_.reset();
- } else {
+ if (delegate->GetSessionStartTime(&session_start_time_) &&
+ delegate->GetSessionLengthLimit(&time_limit_)) {
+ const base::TimeDelta expiring_soon_threshold(
+ base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes));
remaining_session_time_ = std::max(
- limit_ - (base::TimeTicks::Now() - session_start_time_),
+ time_limit_ - (base::TimeTicks::Now() - session_start_time_),
base::TimeDelta());
- limit_state_ = remaining_session_time_.InSeconds() <=
- kExpiringSoonThresholdInSeconds ? LIMIT_EXPIRING_SOON : LIMIT_SET;
+ limit_state_ = remaining_session_time_ <= expiring_soon_threshold ?
+ LIMIT_EXPIRING_SOON : LIMIT_SET;
if (!timer_)
timer_.reset(new base::RepeatingTimer<TraySessionLengthLimit>);
if (!timer_->IsRunning()) {
- // Start a timer that will update the remaining session time every second.
timer_->Start(FROM_HERE,
- base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromMilliseconds(
+ kTimerIntervalInMilliseconds),
this,
&TraySessionLengthLimit::Update);
}
+ } else {
+ remaining_session_time_ = base::TimeDelta();
+ limit_state_ = LIMIT_NONE;
+ timer_.reset();
}
+}
- switch (limit_state_) {
- case LIMIT_NONE:
- message_center::MessageCenter::Get()->RemoveNotification(
- kNotificationId, false /* by_user */);
- break;
- case LIMIT_SET:
- CreateOrUpdateNotification(
- kNotificationId,
- remaining_session_time_,
- previous_limit_state == LIMIT_NONE);
- break;
- case LIMIT_EXPIRING_SOON:
- CreateOrUpdateNotification(
- kNotificationId,
- remaining_session_time_,
- previous_limit_state == LIMIT_NONE ||
- previous_limit_state == LIMIT_SET);
- break;
+void TraySessionLengthLimit::UpdateNotification() {
+ message_center::MessageCenter* message_center =
+ message_center::MessageCenter::Get();
+
+ // If state hasn't changed and the notification has already been acknowledged,
+ // we won't re-create it.
+ if (limit_state_ == last_limit_state_ &&
+ !message_center->HasNotification(kNotificationId)) {
+ return;
+ }
+
+ // After state change, any possibly existing notification is removed to make
+ // sure it is re-shown even if it had been acknowledged by the user before
+ // (and in the rare case of state change towards LIMIT_NONE to make the
+ // notification disappear).
+ if (limit_state_ != last_limit_state_ &&
+ message_center->HasNotification(kNotificationId)) {
+ message_center::MessageCenter::Get()->RemoveNotification(
+ kNotificationId, false /* by_user */);
+ }
+
+ // For LIMIT_NONE, there's nothing more to do.
+ if (limit_state_ == LIMIT_NONE) {
+ last_limit_state_ = limit_state_;
+ return;
}
- // Update the tray view last so that it can check whether the notification
- // view is currently visible or not.
- if (tray_view_)
- tray_view_->Update();
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ message_center::RichNotificationData data;
+ data.should_make_spoken_feedback_for_popup_updates =
+ (limit_state_ != last_limit_state_);
+ scoped_ptr<message_center::Notification> notification(
+ new message_center::Notification(
+ message_center::NOTIFICATION_TYPE_SIMPLE,
+ kNotificationId,
+ base::string16() /* title */,
+ ComposeNotificationMessage() /* message */,
+ bundle.GetImageNamed(
+ IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT),
+ base::string16() /* display_source */,
+ message_center::NotifierId(
+ message_center::NotifierId::SYSTEM_COMPONENT,
+ system_notifier::kNotifierSessionLengthTimeout),
+ data,
+ NULL /* delegate */));
+ notification->SetSystemPriority();
+ if (message_center->HasNotification(kNotificationId))
+ message_center->UpdateNotification(kNotificationId, notification.Pass());
+ else
+ message_center->AddNotification(notification.Pass());
+ last_limit_state_ = limit_state_;
+}
+
+void TraySessionLengthLimit::UpdateTrayBubbleView() const {
+ if (!tray_bubble_view_)
+ return;
+ if (limit_state_ == LIMIT_NONE)
+ tray_bubble_view_->SetMessage(base::string16());
+ else
+ tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
+ tray_bubble_view_->Layout();
+}
+
+base::string16 TraySessionLengthLimit::ComposeNotificationMessage() const {
+ return l10n_util::GetStringFUTF16(
+ IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT,
+ ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
+ ui::TimeFormat::LENGTH_LONG,
+ 10,
+ remaining_session_time_));
}
-bool TraySessionLengthLimit::IsTrayViewVisibleForTest() {
- return tray_view_ && tray_view_->visible();
+base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
+ return l10n_util::GetStringFUTF16(
+ IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT,
+ ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
+ ui::TimeFormat::LENGTH_LONG,
+ 10,
+ remaining_session_time_));
}
} // namespace ash

Powered by Google App Engine
This is Rietveld 408576698