Commit 9090a19d authored by Tetsui Ohkubo's avatar Tetsui Ohkubo Committed by Commit Bot

Split model from TraySessionLengthLimit.

Model variables and logic were stored in TraySessionLengthLimit. This CL
adds SessionLengthLimitModel to SystemTrayModel and separates them.

In the upcoming CL, session length limit notification will be generated
outside TraySessionLengthLimit, as it will be removed with
UnifiedSystemTray launch.

TEST=TraySessionLengthLimitTest
BUG=none

Change-Id: Ic3994f45f0ad48460654512fa8f8e23874503a73
Reviewed-on: https://chromium-review.googlesource.com/1015444Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Commit-Queue: Tetsui Ohkubo <tetsui@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551534}
parent ae9ef309
......@@ -577,6 +577,8 @@ component("ash") {
"system/model/clock_model.h",
"system/model/enterprise_domain_model.cc",
"system/model/enterprise_domain_model.h",
"system/model/session_length_limit_model.cc",
"system/model/session_length_limit_model.h",
"system/model/system_tray_model.cc",
"system/model/system_tray_model.h",
"system/model/tracing_model.cc",
......
......@@ -917,6 +917,8 @@ Shell::~Shell() {
// Destroys the MessageCenter singleton, so must happen late.
message_center_controller_.reset();
system_tray_model_.reset();
local_state_.reset();
shell_delegate_.reset();
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/model/session_length_limit_model.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
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 kExpiringSoonThresholdInMinutes = 5;
// 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
SessionLengthLimitModel::SessionLengthLimitModel() {
Shell::Get()->session_controller()->AddObserver(this);
}
SessionLengthLimitModel::~SessionLengthLimitModel() {
Shell::Get()->session_controller()->RemoveObserver(this);
}
void SessionLengthLimitModel::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void SessionLengthLimitModel::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void SessionLengthLimitModel::OnSessionStateChanged(
session_manager::SessionState state) {
Update();
}
void SessionLengthLimitModel::OnSessionLengthLimitChanged() {
Update();
}
void SessionLengthLimitModel::Update() {
if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted())
return;
SessionController* session = Shell::Get()->session_controller();
base::TimeDelta time_limit = session->session_length_limit();
base::TimeTicks session_start_time = session->session_start_time();
if (!time_limit.is_zero() && !session_start_time.is_null()) {
const base::TimeDelta expiring_soon_threshold(
base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes));
remaining_session_time_ =
std::max(time_limit - (base::TimeTicks::Now() - session_start_time),
base::TimeDelta());
limit_state_ = remaining_session_time_ <= expiring_soon_threshold
? LIMIT_EXPIRING_SOON
: LIMIT_SET;
if (!timer_)
timer_ = std::make_unique<base::RepeatingTimer>();
if (!timer_->IsRunning()) {
timer_->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kTimerIntervalInMilliseconds), this,
&SessionLengthLimitModel::Update);
}
} else {
remaining_session_time_ = base::TimeDelta();
limit_state_ = LIMIT_NONE;
timer_.reset();
}
for (auto& observer : observers_)
observer.OnSessionLengthLimitUpdated();
}
} // namespace ash
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_MODEL_SESSION_LENGTH_LIMIT_MODEL_H_
#define ASH_SYSTEM_MODEL_SESSION_LENGTH_LIMIT_MODEL_H_
#include "ash/session/session_observer.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
namespace ash {
// Model to manage coutdown timer when the session length is limited.
class SessionLengthLimitModel : public SessionObserver {
public:
class Observer {
public:
virtual ~Observer() {}
// Called when |remaining_session_time| or |limit_state| is updated.
virtual void OnSessionLengthLimitUpdated() = 0;
};
// LIMIT_NONE: The session does not have length limit.
// LIMIT_SET: The session has length limit.
// LIMIT_EXPIRING_SOON: The session will expire soon.
enum LimitState { LIMIT_NONE, LIMIT_SET, LIMIT_EXPIRING_SOON };
SessionLengthLimitModel();
~SessionLengthLimitModel() override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
void OnSessionLengthLimitChanged() override;
base::TimeDelta remaining_session_time() const {
return remaining_session_time_;
}
LimitState limit_state() const { return limit_state_; }
private:
// Recalculate |limit_state_| and |remaining_session_time_|.
void Update();
base::TimeDelta remaining_session_time_;
LimitState limit_state_ = LIMIT_NONE;
std::unique_ptr<base::RepeatingTimer> timer_;
base::ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(SessionLengthLimitModel);
};
} // namespace ash
#endif // ASH_SYSTEM_MODEL_SESSION_LENGTH_LIMIT_MODEL_H_
......@@ -6,6 +6,7 @@
#include "ash/system/model/clock_model.h"
#include "ash/system/model/enterprise_domain_model.h"
#include "ash/system/model/session_length_limit_model.h"
#include "ash/system/model/tracing_model.h"
#include "ash/system/model/update_model.h"
#include "base/logging.h"
......@@ -15,6 +16,7 @@ namespace ash {
SystemTrayModel::SystemTrayModel()
: clock_(std::make_unique<ClockModel>()),
enterprise_domain_(std::make_unique<EnterpriseDomainModel>()),
session_length_limit_(std::make_unique<SessionLengthLimitModel>()),
tracing_(std::make_unique<TracingModel>()),
update_model_(std::make_unique<UpdateModel>()) {}
......
......@@ -14,6 +14,7 @@ namespace ash {
class ClockModel;
class EnterpriseDomainModel;
class SessionLengthLimitModel;
class TracingModel;
class UpdateModel;
......@@ -42,12 +43,16 @@ class SystemTrayModel : public mojom::SystemTray {
EnterpriseDomainModel* enterprise_domain() {
return enterprise_domain_.get();
}
SessionLengthLimitModel* session_length_limit() {
return session_length_limit_.get();
}
TracingModel* tracing() { return tracing_.get(); }
UpdateModel* update_model() { return update_model_.get(); }
private:
std::unique_ptr<ClockModel> clock_;
std::unique_ptr<EnterpriseDomainModel> enterprise_domain_;
std::unique_ptr<SessionLengthLimitModel> session_length_limit_;
std::unique_ptr<TracingModel> tracing_;
std::unique_ptr<UpdateModel> update_model_;
......
......@@ -12,6 +12,8 @@
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/model/session_length_limit_model.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/tray/label_tray_view.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_notifier.h"
......@@ -30,21 +32,12 @@ namespace {
const char kNotifierSessionLengthTimeout[] = "ash.session-length-timeout";
// If the remaining session time falls below this threshold, the user should be
// informed that the session is about to expire.
const int kExpiringSoonThresholdInMinutes = 5;
// A notification is shown to the user only if the remaining session time falls
// under this threshold. e.g. If the user has several days left in their
// session, there is no use displaying a notification right now.
constexpr base::TimeDelta kNotificationThreshold =
base::TimeDelta::FromMinutes(60);
// 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
// static
......@@ -53,23 +46,19 @@ const char TraySessionLengthLimit::kNotificationId[] =
TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray)
: SystemTrayItem(system_tray, UMA_SESSION_LENGTH_LIMIT),
limit_state_(LIMIT_NONE),
last_limit_state_(LIMIT_NONE),
has_notification_been_shown_(false),
tray_bubble_view_(nullptr) {
Shell::Get()->session_controller()->AddObserver(this);
Update();
model_(Shell::Get()->system_tray_model()->session_length_limit()) {
model_->AddObserver(this);
OnSessionLengthLimitUpdated();
}
TraySessionLengthLimit::~TraySessionLengthLimit() {
Shell::Get()->session_controller()->RemoveObserver(this);
model_->RemoveObserver(this);
}
// Add view to tray bubble.
views::View* TraySessionLengthLimit::CreateDefaultView(LoginStatus status) {
CHECK(!tray_bubble_view_);
UpdateState();
if (limit_state_ == LIMIT_NONE)
if (model_->limit_state() == SessionLengthLimitModel::LIMIT_NONE)
return nullptr;
tray_bubble_view_ = new LabelTrayView(nullptr, kSystemMenuTimerIcon);
tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
......@@ -81,50 +70,14 @@ void TraySessionLengthLimit::OnDefaultViewDestroyed() {
tray_bubble_view_ = nullptr;
}
void TraySessionLengthLimit::OnSessionStateChanged(
session_manager::SessionState state) {
Update();
}
void TraySessionLengthLimit::OnSessionLengthLimitChanged() {
Update();
}
void TraySessionLengthLimit::Update() {
void TraySessionLengthLimit::OnSessionLengthLimitUpdated() {
// Don't show notification or tray item until the user is logged in.
if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted())
return;
UpdateState();
UpdateNotification();
UpdateTrayBubbleView();
}
void TraySessionLengthLimit::UpdateState() {
SessionController* session = Shell::Get()->session_controller();
base::TimeDelta time_limit = session->session_length_limit();
base::TimeTicks session_start_time = session->session_start_time();
if (!time_limit.is_zero() && !session_start_time.is_null()) {
const base::TimeDelta expiring_soon_threshold(
base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes));
remaining_session_time_ =
std::max(time_limit - (base::TimeTicks::Now() - session_start_time),
base::TimeDelta());
limit_state_ = remaining_session_time_ <= expiring_soon_threshold
? LIMIT_EXPIRING_SOON
: LIMIT_SET;
if (!timer_)
timer_.reset(new base::RepeatingTimer);
if (!timer_->IsRunning()) {
timer_->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
kTimerIntervalInMilliseconds),
this, &TraySessionLengthLimit::Update);
}
} else {
remaining_session_time_ = base::TimeDelta();
limit_state_ = LIMIT_NONE;
timer_.reset();
}
last_limit_state_ = model_->limit_state();
}
void TraySessionLengthLimit::UpdateNotification() {
......@@ -134,7 +87,8 @@ void TraySessionLengthLimit::UpdateNotification() {
// If state hasn't changed and the notification has already been acknowledged,
// we won't re-create it. We consider a notification to be acknowledged if it
// was shown before, but is no longer visible.
if (limit_state_ == last_limit_state_ && has_notification_been_shown_ &&
if (model_->limit_state() == last_limit_state_ &&
has_notification_been_shown_ &&
!message_center->FindVisibleNotificationById(kNotificationId)) {
return;
}
......@@ -143,7 +97,7 @@ void TraySessionLengthLimit::UpdateNotification() {
// 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_ &&
if (model_->limit_state() != last_limit_state_ &&
message_center->FindVisibleNotificationById(kNotificationId)) {
message_center::MessageCenter::Get()->RemoveNotification(
kNotificationId, false /* by_user */);
......@@ -151,15 +105,14 @@ void TraySessionLengthLimit::UpdateNotification() {
// If the session is unlimited or if the remaining time is too far off into
// the future, there is nothing more to do.
if (limit_state_ == LIMIT_NONE ||
remaining_session_time_ > kNotificationThreshold) {
last_limit_state_ = limit_state_;
if (model_->limit_state() == SessionLengthLimitModel::LIMIT_NONE ||
model_->remaining_session_time() > kNotificationThreshold) {
return;
}
message_center::RichNotificationData data;
data.should_make_spoken_feedback_for_popup_updates =
(limit_state_ != last_limit_state_);
(model_->limit_state() != last_limit_state_);
std::unique_ptr<message_center::Notification> notification =
message_center::Notification::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
......@@ -180,13 +133,12 @@ void TraySessionLengthLimit::UpdateNotification() {
message_center->AddNotification(std::move(notification));
}
has_notification_been_shown_ = true;
last_limit_state_ = limit_state_;
}
void TraySessionLengthLimit::UpdateTrayBubbleView() const {
if (!tray_bubble_view_)
return;
if (limit_state_ == LIMIT_NONE)
if (model_->limit_state() == SessionLengthLimitModel::LIMIT_NONE)
tray_bubble_view_->SetMessage(base::string16());
else
tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage());
......@@ -198,7 +150,7 @@ base::string16 TraySessionLengthLimit::ComposeNotificationTitle() const {
IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT_TITLE,
ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
ui::TimeFormat::LENGTH_SHORT,
remaining_session_time_));
model_->remaining_session_time()));
}
base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
......@@ -206,7 +158,7 @@ base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const {
IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT,
ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION,
ui::TimeFormat::LENGTH_LONG, 10,
remaining_session_time_));
model_->remaining_session_time()));
}
} // namespace ash
......@@ -7,23 +7,20 @@
#include <memory>
#include "ash/session/session_observer.h"
#include "ash/system/model/session_length_limit_model.h"
#include "ash/system/tray/system_tray_item.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
namespace ash {
class LabelTrayView;
// Adds a countdown timer to the system tray if the session length is limited.
class ASH_EXPORT TraySessionLengthLimit : public SystemTrayItem,
public SessionObserver {
class ASH_EXPORT TraySessionLengthLimit
: public SystemTrayItem,
public SessionLengthLimitModel::Observer {
public:
enum LimitState { LIMIT_NONE, LIMIT_SET, LIMIT_EXPIRING_SOON };
explicit TraySessionLengthLimit(SystemTray* system_tray);
~TraySessionLengthLimit() override;
......@@ -31,22 +28,14 @@ class ASH_EXPORT TraySessionLengthLimit : public SystemTrayItem,
views::View* CreateDefaultView(LoginStatus status) override;
void OnDefaultViewDestroyed() override;
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
void OnSessionLengthLimitChanged() override;
// SessionLengthLimitModel::Observer:
void OnSessionLengthLimitUpdated() override;
private:
friend class TraySessionLengthLimitTest;
static const char kNotificationId[];
// Update state, notification and tray bubble view. Called by the
// RepeatingTimer in regular intervals and also by OnSession*Changed().
void Update();
// Recalculate |limit_state_| and |remaining_session_time_|.
void UpdateState();
void UpdateNotification();
void UpdateTrayBubbleView() const;
......@@ -54,14 +43,16 @@ class ASH_EXPORT TraySessionLengthLimit : public SystemTrayItem,
base::string16 ComposeNotificationTitle() const;
base::string16 ComposeTrayBubbleMessage() const;
base::TimeDelta remaining_session_time_;
// Unowned.
SessionLengthLimitModel* const model_;
// LimitState of the last time OnSessionLengthLimitUpdate() is called.
SessionLengthLimitModel::LimitState last_limit_state_ =
SessionLengthLimitModel::LIMIT_NONE;
LimitState limit_state_; // Current state.
LimitState last_limit_state_; // State of last notification update.
bool has_notification_been_shown_;
bool has_notification_been_shown_ = false;
LabelTrayView* tray_bubble_view_;
std::unique_ptr<base::RepeatingTimer> timer_;
LabelTrayView* tray_bubble_view_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TraySessionLengthLimit);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment