Commit 73baa65c authored by Tetsui Ohkubo's avatar Tetsui Ohkubo Committed by Commit Bot

Generate supervised user notification outside tray

Supervised user notification was generated in TraySupervisedUser, which
is a SystemTrayItem.

We're going to get rid of SystemTrayItems as UnifiedSystemTray will
replace them, so we should generate the notification outside system
tray.

TEST=SupervisedNotificationControllerTest
BUG=none

Change-Id: Ifc774e83eb28e996f3f337040f31d736ab8e5f52
Reviewed-on: https://chromium-review.googlesource.com/1013117Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: Tetsui Ohkubo <tetsui@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551122}
parent e7171fc1
......@@ -716,6 +716,8 @@ component("ash") {
"system/status_area_widget.h",
"system/status_area_widget_delegate.cc",
"system/status_area_widget_delegate.h",
"system/supervised/supervised_notification_controller.cc",
"system/supervised/supervised_notification_controller.h",
"system/supervised/tray_supervised_user.cc",
"system/supervised/tray_supervised_user.h",
"system/system_tray_focus_observer.h",
......@@ -1632,6 +1634,7 @@ test("ash_unittests") {
"system/session/logout_confirmation_controller_unittest.cc",
"system/session/tray_session_length_limit_unittest.cc",
"system/status_area_widget_unittest.cc",
"system/supervised/supervised_notification_controller_unittest.cc",
"system/supervised/tray_supervised_user_unittest.cc",
"system/tiles/tray_tiles_unittest.cc",
"system/toast/toast_manager_unittest.cc",
......
......@@ -106,6 +106,7 @@
#include "ash/system/session/logout_button_tray.h"
#include "ash/system/session/logout_confirmation_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/supervised/supervised_notification_controller.h"
#include "ash/system/toast/toast_manager.h"
#include "ash/system/tray/system_tray_controller.h"
#include "ash/system/tray/system_tray_notifier.h"
......@@ -831,6 +832,7 @@ Shell::~Shell() {
resolution_notification_controller_.reset();
screen_security_notification_controller_.reset();
screenshot_controller_.reset();
supervised_notification_controller_.reset();
mouse_cursor_filter_.reset();
modality_filter_.reset();
......@@ -944,6 +946,8 @@ void Shell::Init(ui::ContextFactory* context_factory,
detachable_base_handler_.get());
screen_security_notification_controller_ =
std::make_unique<ScreenSecurityNotificationController>();
supervised_notification_controller_ =
std::make_unique<SupervisedNotificationController>();
// Connector can be null in tests.
if (shell_delegate_->GetShellConnector()) {
......
......@@ -160,6 +160,7 @@ class ShutdownController;
class SmsObserver;
class SplitViewController;
class StickyKeysController;
class SupervisedNotificationController;
class SystemGestureEventFilter;
class SystemModalContainerEventFilter;
class SystemTray;
......@@ -716,6 +717,8 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<NoteTakingController> note_taking_controller_;
std::unique_ptr<ScreenSecurityNotificationController>
screen_security_notification_controller_;
std::unique_ptr<SupervisedNotificationController>
supervised_notification_controller_;
std::unique_ptr<ShelfController> shelf_controller_;
std::unique_ptr<ShelfWindowWatcher> shelf_window_watcher_;
std::unique_ptr<ShellDelegate> shell_delegate_;
......
// 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/supervised/supervised_notification_controller.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
using base::UTF8ToUTF16;
using message_center::MessageCenter;
using message_center::Notification;
namespace ash {
namespace {
const char kNotifierSupervisedUser[] = "ash.locally-managed-user";
} // namespace
const char SupervisedNotificationController::kNotificationId[] =
"chrome://user/locally-managed";
SupervisedNotificationController::SupervisedNotificationController() = default;
SupervisedNotificationController::~SupervisedNotificationController() = default;
// static
base::string16 SupervisedNotificationController::GetSupervisedUserMessage() {
SessionController* session_controller = Shell::Get()->session_controller();
DCHECK(session_controller->IsUserSupervised());
DCHECK(session_controller->IsActiveUserSessionStarted());
// Get the active user session.
const mojom::UserSession* const user_session =
session_controller->GetUserSession(0);
DCHECK(user_session);
base::string16 first_custodian = UTF8ToUTF16(user_session->custodian_email);
base::string16 second_custodian =
UTF8ToUTF16(user_session->second_custodian_email);
// Regular supervised user. The "manager" is the first custodian.
if (!Shell::Get()->session_controller()->IsUserChild()) {
return l10n_util::GetStringFUTF16(IDS_ASH_USER_IS_SUPERVISED_BY_NOTICE,
first_custodian);
}
// Child supervised user.
if (second_custodian.empty()) {
return l10n_util::GetStringFUTF16(
IDS_ASH_CHILD_USER_IS_MANAGED_BY_ONE_PARENT_NOTICE, first_custodian);
}
return l10n_util::GetStringFUTF16(
IDS_ASH_CHILD_USER_IS_MANAGED_BY_TWO_PARENTS_NOTICE, first_custodian,
second_custodian);
}
void SupervisedNotificationController::OnActiveUserSessionChanged(
const AccountId& account_id) {
OnUserSessionUpdated(account_id);
}
void SupervisedNotificationController::OnUserSessionAdded(
const AccountId& account_id) {
OnUserSessionUpdated(account_id);
}
void SupervisedNotificationController::OnUserSessionUpdated(
const AccountId& account_id) {
SessionController* session_controller = Shell::Get()->session_controller();
if (!session_controller->IsUserSupervised())
return;
// Get the active user session.
DCHECK(session_controller->IsActiveUserSessionStarted());
const mojom::UserSession* const user_session =
session_controller->GetUserSession(0);
DCHECK(user_session);
// Only respond to updates for the active user.
if (user_session->user_info->account_id != account_id)
return;
// Show notifications when custodian data first becomes available on login
// and if the custodian data changes.
if (custodian_email_ == user_session->custodian_email &&
second_custodian_email_ == user_session->second_custodian_email) {
return;
}
custodian_email_ = user_session->custodian_email;
second_custodian_email_ = user_session->second_custodian_email;
CreateOrUpdateNotification();
}
// static
void SupervisedNotificationController::CreateOrUpdateNotification() {
// No notification for the child user.
if (Shell::Get()->session_controller()->IsUserChild())
return;
// Regular supervised user.
std::unique_ptr<Notification> notification =
Notification::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL),
GetSupervisedUserMessage(), gfx::Image(),
base::string16() /* display_source */, GURL(),
message_center::NotifierId(
message_center::NotifierId::SYSTEM_COMPONENT,
kNotifierSupervisedUser),
message_center::RichNotificationData(), nullptr,
kNotificationSupervisedIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
notification->SetSystemPriority();
// AddNotification does an update if the notification already exists.
MessageCenter::Get()->AddNotification(std::move(notification));
}
} // 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_SUPERVISED_SUPERVISED_NOTIFICATION_CONTROLLER_H_
#define ASH_SYSTEM_SUPERVISED_SUPERVISED_NOTIFICATION_CONTROLLER_H_
#include <string>
#include "ash/ash_export.h"
#include "ash/session/session_observer.h"
#include "base/strings/string16.h"
namespace ash {
// Controller class to manage supervised user notification.
class ASH_EXPORT SupervisedNotificationController : public SessionObserver {
public:
SupervisedNotificationController();
~SupervisedNotificationController() override;
static base::string16 GetSupervisedUserMessage();
// SessionObserver:
void OnActiveUserSessionChanged(const AccountId& account_id) override;
void OnUserSessionAdded(const AccountId& account_id) override;
void OnUserSessionUpdated(const AccountId& account_id) override;
private:
friend class SupervisedNotificationControllerTest;
static const char kNotificationId[];
static void CreateOrUpdateNotification();
std::string custodian_email_;
std::string second_custodian_email_;
ScopedSessionObserver scoped_session_observer_{this};
DISALLOW_COPY_AND_ASSIGN(SupervisedNotificationController);
};
} // namespace ash
#endif // ASH_SYSTEM_SUPERVISED_SUPERVISED_NOTIFICATION_CONTROLLER_H_
// 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/supervised/supervised_notification_controller.h"
#include "ash/session/session_controller.h"
#include "ash/session/test_session_controller_client.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification_list.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
using base::UTF8ToUTF16;
using message_center::NotificationList;
namespace ash {
// Tests handle creating their own sessions.
class SupervisedNotificationControllerTest : public NoSessionAshTestBase {
public:
SupervisedNotificationControllerTest() = default;
~SupervisedNotificationControllerTest() override = default;
protected:
message_center::Notification* GetPopup();
private:
DISALLOW_COPY_AND_ASSIGN(SupervisedNotificationControllerTest);
};
message_center::Notification* SupervisedNotificationControllerTest::GetPopup() {
NotificationList::PopupNotifications popups =
message_center::MessageCenter::Get()->GetPopupNotifications();
for (NotificationList::PopupNotifications::const_iterator iter =
popups.begin();
iter != popups.end(); ++iter) {
if ((*iter)->id() == SupervisedNotificationController::kNotificationId)
return *iter;
}
return NULL;
}
// Verifies that when a supervised user logs in that a warning notification is
// shown and ash does not crash.
TEST_F(SupervisedNotificationControllerTest, SupervisedUserHasNotification) {
SessionController* session = Shell::Get()->session_controller();
ASSERT_EQ(LoginStatus::NOT_LOGGED_IN, session->login_status());
ASSERT_FALSE(session->IsActiveUserSessionStarted());
// Simulate a supervised user logging in.
TestSessionControllerClient* client = GetSessionControllerClient();
client->Reset();
client->AddUserSession("child@test.com", user_manager::USER_TYPE_SUPERVISED);
client->SetSessionState(session_manager::SessionState::ACTIVE);
// No notification because custodian email not available yet.
message_center::Notification* notification = GetPopup();
EXPECT_FALSE(notification);
const std::string custodian_email = "parent1@test.com";
const std::string custodian_email2 = "parent2@test.com";
// Update the user session with the custodian data (which happens after the
// profile loads).
mojom::UserSessionPtr user_session = session->GetUserSession(0)->Clone();
user_session->custodian_email = custodian_email;
session->UpdateUserSession(std::move(user_session));
// Notification is shown.
notification = GetPopup();
ASSERT_TRUE(notification);
EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY),
notification->rich_notification_data().priority);
EXPECT_NE(base::string16::npos,
notification->message().find(UTF8ToUTF16(custodian_email)));
// Update the user session with new custodian data.
user_session = session->GetUserSession(0)->Clone();
user_session->custodian_email = custodian_email2;
session->UpdateUserSession(std::move(user_session));
// Notification is shown with updated message.
notification = GetPopup();
ASSERT_TRUE(notification);
EXPECT_EQ(base::string16::npos,
notification->message().find(UTF8ToUTF16(custodian_email)));
EXPECT_NE(base::string16::npos,
notification->message().find(UTF8ToUTF16(custodian_email2)));
}
} // namespace ash
......@@ -10,26 +10,16 @@
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/supervised/supervised_notification_controller.h"
#include "ash/system/tray/label_tray_view.h"
#include "ash/system/tray/tray_constants.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
using base::UTF8ToUTF16;
using message_center::MessageCenter;
using message_center::Notification;
namespace ash {
namespace {
const char kNotifierSupervisedUser[] = "ash.locally-managed-user";
const gfx::VectorIcon& GetSupervisedUserIcon() {
SessionController* session_controller = Shell::Get()->session_controller();
DCHECK(session_controller->IsUserSupervised());
......@@ -42,12 +32,8 @@ const gfx::VectorIcon& GetSupervisedUserIcon() {
} // namespace
const char TraySupervisedUser::kNotificationId[] =
"chrome://user/locally-managed";
TraySupervisedUser::TraySupervisedUser(SystemTray* system_tray)
: SystemTrayItem(system_tray, UMA_SUPERVISED_USER),
scoped_session_observer_(this) {}
: SystemTrayItem(system_tray, UMA_SUPERVISED_USER) {}
TraySupervisedUser::~TraySupervisedUser() = default;
......@@ -59,87 +45,9 @@ views::View* TraySupervisedUser::CreateDefaultView(LoginStatus status) {
new LabelTrayView(nullptr, GetSupervisedUserIcon());
// The message almost never changes during a session, so we compute it when
// the menu is shown. We don't update it while the menu is open.
tray_view->SetMessage(GetSupervisedUserMessage());
tray_view->SetMessage(
SupervisedNotificationController::GetSupervisedUserMessage());
return tray_view;
}
void TraySupervisedUser::OnActiveUserSessionChanged(
const AccountId& account_id) {
OnUserSessionUpdated(account_id);
}
void TraySupervisedUser::OnUserSessionAdded(const AccountId& account_id) {
OnUserSessionUpdated(account_id);
}
void TraySupervisedUser::OnUserSessionUpdated(const AccountId& account_id) {
SessionController* session_controller = Shell::Get()->session_controller();
if (!session_controller->IsUserSupervised())
return;
// Get the active user session.
DCHECK(session_controller->IsActiveUserSessionStarted());
const mojom::UserSession* const user_session =
session_controller->GetUserSession(0);
DCHECK(user_session);
// Only respond to updates for the active user.
if (user_session->user_info->account_id != account_id)
return;
// Show notifications when custodian data first becomes available on login
// and if the custodian data changes.
if (custodian_email_ == user_session->custodian_email &&
second_custodian_email_ == user_session->second_custodian_email) {
return;
}
custodian_email_ = user_session->custodian_email;
second_custodian_email_ = user_session->second_custodian_email;
CreateOrUpdateNotification();
}
void TraySupervisedUser::CreateOrUpdateNotification() {
// No notification for the child user.
if (Shell::Get()->session_controller()->IsUserChild())
return;
// Regular supervised user.
std::unique_ptr<Notification> notification =
Notification::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL),
GetSupervisedUserMessage(), gfx::Image(),
base::string16() /* display_source */, GURL(),
message_center::NotifierId(
message_center::NotifierId::SYSTEM_COMPONENT,
kNotifierSupervisedUser),
message_center::RichNotificationData(), nullptr,
kNotificationSupervisedIcon,
message_center::SystemNotificationWarningLevel::NORMAL);
notification->SetSystemPriority();
// AddNotification does an update if the notification already exists.
MessageCenter::Get()->AddNotification(std::move(notification));
}
base::string16 TraySupervisedUser::GetSupervisedUserMessage() const {
base::string16 first_custodian = UTF8ToUTF16(custodian_email_);
base::string16 second_custodian = UTF8ToUTF16(second_custodian_email_);
// Regular supervised user. The "manager" is the first custodian.
if (!Shell::Get()->session_controller()->IsUserChild()) {
return l10n_util::GetStringFUTF16(IDS_ASH_USER_IS_SUPERVISED_BY_NOTICE,
first_custodian);
}
// Child supervised user.
if (second_custodian.empty()) {
return l10n_util::GetStringFUTF16(
IDS_ASH_CHILD_USER_IS_MANAGED_BY_ONE_PARENT_NOTICE, first_custodian);
}
return l10n_util::GetStringFUTF16(
IDS_ASH_CHILD_USER_IS_MANAGED_BY_TWO_PARENTS_NOTICE, first_custodian,
second_custodian);
}
} // namespace ash
......@@ -18,8 +18,7 @@ class SystemTray;
// System tray item that shows a message if the user is supervised or a child.
// Also shows a notification on login if the user is supervised. Shows a new
// notification if the user manager/custodian changes.
class ASH_EXPORT TraySupervisedUser : public SystemTrayItem,
public SessionObserver {
class ASH_EXPORT TraySupervisedUser : public SystemTrayItem {
public:
explicit TraySupervisedUser(SystemTray* system_tray);
~TraySupervisedUser() override;
......@@ -27,25 +26,7 @@ class ASH_EXPORT TraySupervisedUser : public SystemTrayItem,
// SystemTrayItem:
views::View* CreateDefaultView(LoginStatus status) override;
// SessionObserver:
void OnActiveUserSessionChanged(const AccountId& account_id) override;
void OnUserSessionAdded(const AccountId& account_id) override;
void OnUserSessionUpdated(const AccountId& account_id) override;
private:
friend class TraySupervisedUserTest;
static const char kNotificationId[];
void CreateOrUpdateNotification();
base::string16 GetSupervisedUserMessage() const;
std::string custodian_email_;
std::string second_custodian_email_;
ScopedSessionObserver scoped_session_observer_;
DISALLOW_COPY_AND_ASSIGN(TraySupervisedUser);
};
......
......@@ -14,88 +14,13 @@
#include "ash/test/ash_test_base.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification_list.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "ui/views/view.h"
using base::UTF16ToUTF8;
using message_center::NotificationList;
namespace ash {
// Tests handle creating their own sessions.
class TraySupervisedUserTest : public NoSessionAshTestBase {
public:
TraySupervisedUserTest() = default;
~TraySupervisedUserTest() override = default;
protected:
message_center::Notification* GetPopup();
private:
DISALLOW_COPY_AND_ASSIGN(TraySupervisedUserTest);
};
message_center::Notification* TraySupervisedUserTest::GetPopup() {
NotificationList::PopupNotifications popups =
message_center::MessageCenter::Get()->GetPopupNotifications();
for (NotificationList::PopupNotifications::const_iterator iter =
popups.begin();
iter != popups.end(); ++iter) {
if ((*iter)->id() == TraySupervisedUser::kNotificationId)
return *iter;
}
return NULL;
}
// Verifies that when a supervised user logs in that a warning notification is
// shown and ash does not crash.
TEST_F(TraySupervisedUserTest, SupervisedUserHasNotification) {
SessionController* session = Shell::Get()->session_controller();
ASSERT_EQ(LoginStatus::NOT_LOGGED_IN, session->login_status());
ASSERT_FALSE(session->IsActiveUserSessionStarted());
// Simulate a supervised user logging in.
TestSessionControllerClient* client = GetSessionControllerClient();
client->Reset();
client->AddUserSession("child@test.com", user_manager::USER_TYPE_SUPERVISED);
client->SetSessionState(session_manager::SessionState::ACTIVE);
// No notification because custodian email not available yet.
message_center::Notification* notification = GetPopup();
EXPECT_FALSE(notification);
// Update the user session with the custodian data (which happens after the
// profile loads).
mojom::UserSessionPtr user_session = session->GetUserSession(0)->Clone();
user_session->custodian_email = "parent1@test.com";
session->UpdateUserSession(std::move(user_session));
// Notification is shown.
notification = GetPopup();
ASSERT_TRUE(notification);
EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY),
notification->rich_notification_data().priority);
EXPECT_EQ(
"Usage and history of this user can be reviewed by the manager "
"(parent1@test.com) on chrome.com.",
UTF16ToUTF8(notification->message()));
// Update the user session with new custodian data.
user_session = session->GetUserSession(0)->Clone();
user_session->custodian_email = "parent2@test.com";
session->UpdateUserSession(std::move(user_session));
// Notification is shown with updated message.
notification = GetPopup();
ASSERT_TRUE(notification);
EXPECT_EQ(
"Usage and history of this user can be reviewed by the manager "
"(parent2@test.com) on chrome.com.",
UTF16ToUTF8(notification->message()));
}
using TraySupervisedUserTest = NoSessionAshTestBase;
// Verifies an item is created for a supervised user.
TEST_F(TraySupervisedUserTest, CreateDefaultView) {
......
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