Commit a3630ee9 authored by Saurabh Nijhara's avatar Saurabh Nijhara Committed by Commit Bot

Minimum chrome version notifications for EOL and metered network

This CL introduces the handling of showing in-session notifications
when update is required as per the policy but the device is
connected to a metered network or has reached end-of-life(EOL).

In case of metered network -
The notification is to be shown when the policy is received and on the
last day of the deadline. Clicking on the notification button starts
update process over metered connection.
For end-of-life devices -
The notification is to be shown when the policy is received, one week
before deadline and on the last day of the deadline. Clicking on the
notification button opens the enterprise/management info page which
would contain details about the end-of-life of the device.

This detail on the settings page will be implemented in subsequent CL.
New browser and unit tests are also included to verify this behavior.

Bug: 1048607
Change-Id: I4c09a00a50ff1673db1b15e4f05a4a29e825f043
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245612
Commit-Queue: Saurabh Nijhara <snijhara@google.com>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarRoman Sorokin [CET] <rsorokin@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779964}
parent 261add5c
...@@ -2831,15 +2831,37 @@ ...@@ -2831,15 +2831,37 @@
</message> </message>
<!-- Update Required Notiifcation Strings--> <!-- Update Required Notiifcation Strings-->
<message name="IDS_UPDATE_REQUIRED_NO_NETWORK_TITLE_IMMEDIATE" desc="The title of the notification dialog informing the user that the device is not connected to the internet and it is last day to update the device."> <message name="IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS" desc="The title of the notification dialog informing the user that the device is not connected to a network suitable for downloading updates and an update is required within one or more days.">
Last day to update device {0, plural,
</message> =1 {Last day to update device}
<message name="IDS_UPDATE_REQUIRED_NO_NETWORK_TITLE_DAYS" desc="The title of the notification dialog informing the user that the device is not connected to the internet and an update is required within two or more days."> other {Update device within # days}}
Update device within <ph name="COUNT">$1<ex>2</ex></ph> days
</message> </message>
<message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and an update is required."> <message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and an update is required.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to download an update before the deadline. The update will download automatically when you connect to the internet. <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to download an update before the deadline. The update will download automatically when you connect to the internet.
</message> </message>
<message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and it is last day to update the device.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to download an update today. The update will download automatically when you connect to the internet.
</message>
<message name="IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is connected to a metered network and an update is required.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi and download an update before the deadline. Or, download from a metered connection (charges may apply).
</message>
<message name="IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE" desc="The body text of the notification dialog informing the user that the device is connected to a metered network and it is last day to update the device.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi today to download an update. Or, download from a metered connection (charges may apply).
</message>
<message name="IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS" desc="The title of the notification dialog informing the user that the device has reached end of life and should be returned before the deadline.">
{0, plural,
=1 {Immediate return required}
other {Return device within # days}}
</message>
<message name="IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE" desc="The body text of the noti fication dialog informing the user that the device has reached end of life and it is last day to return it.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device today.
</message>
<message name="IDS_UPDATE_REQUIRED_EOL_MESSAGE" desc="The body text of the notification dialog informing the user that the device has reached end of life and should be returned before the deadline.">
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device before the deadline.
</message>
<message name="IDS_UPDATE_REQUIRED_EOL_SEE_DETAILS" desc="The button text of the notification dialog which can be clicked to view return instructions from the admin on the settings page.">
See Details
</message>
<!-- Genius App --> <!-- Genius App -->
<message name="IDS_GENIUS_APP_NAME" desc="Name of the genius app in the app shelf"> <message name="IDS_GENIUS_APP_NAME" desc="Name of the genius app in the app shelf">
......
ef5ea1960e83040ecd2930f349fa065c7875d03d
\ No newline at end of file
80bc5fa9690ddee420644429152296d4ba2e7153
\ No newline at end of file
80bc5fa9690ddee420644429152296d4ba2e7153
\ No newline at end of file
4d497d66d7829e0d8be46d583e5c0f251e6eb1a3
\ No newline at end of file
5df42bf902f65d3b396f473a5fe005c7423a7928
\ No newline at end of file
3f66b8884699b0543805014357c4d33445f39f9e
\ No newline at end of file
43c7e98e139718809dc6ccb93f9e43d5d5cfa358
\ No newline at end of file
e84e0bdb02c3edb288972353dad9c251c500039a
\ No newline at end of file
8e54c107cee1c0dac8732954ab1becef6950dfda
\ No newline at end of file
9ea4bcaf0a870ea64b4655fc089016241dbb3f35
\ No newline at end of file
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/minimum_version_policy_handler_delegate_impl.h" #include "chrome/browser/chromeos/policy/minimum_version_policy_handler_delegate_impl.h"
#include "chrome/browser/chromeos/ui/update_required_notification.h" #include "chrome/browser/chromeos/ui/update_required_notification.h"
#include "chrome/browser/ui/ash/system_tray_client.h"
#include "chrome/browser/upgrade_detector/build_state.h" #include "chrome/browser/upgrade_detector/build_state.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
...@@ -57,6 +58,10 @@ void OpenNetworkSettings() { ...@@ -57,6 +58,10 @@ void OpenNetworkSettings() {
true /* show_by_click */); true /* show_by_click */);
} }
void OpenEnterpriseInfoPage() {
SystemTrayClient::Get()->ShowEnterpriseInfo();
}
std::string GetEnterpriseDomainName() { std::string GetEnterpriseDomainName() {
return g_browser_process->platform_part() return g_browser_process->platform_part()
->browser_policy_connector_chromeos() ->browser_policy_connector_chromeos()
...@@ -72,6 +77,10 @@ int GetDaysRounded(base::TimeDelta time) { ...@@ -72,6 +77,10 @@ int GetDaysRounded(base::TimeDelta time) {
base::TimeDelta::FromDays(1).InSecondsF()); base::TimeDelta::FromDays(1).InSecondsF());
} }
chromeos::UpdateEngineClient* GetUpdateEngineClient() {
return chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
}
} // namespace } // namespace
const char MinimumVersionPolicyHandler::kChromeVersion[] = "chrome_version"; const char MinimumVersionPolicyHandler::kChromeVersion[] = "chrome_version";
...@@ -136,6 +145,7 @@ MinimumVersionPolicyHandler::MinimumVersionPolicyHandler( ...@@ -136,6 +145,7 @@ MinimumVersionPolicyHandler::MinimumVersionPolicyHandler(
MinimumVersionPolicyHandler::~MinimumVersionPolicyHandler() { MinimumVersionPolicyHandler::~MinimumVersionPolicyHandler() {
GetBuildState()->RemoveObserver(this); GetBuildState()->RemoveObserver(this);
StopObservingNetwork(); StopObservingNetwork();
GetUpdateEngineClient()->RemoveObserver(this);
} }
void MinimumVersionPolicyHandler::AddObserver(Observer* observer) { void MinimumVersionPolicyHandler::AddObserver(Observer* observer) {
...@@ -272,10 +282,8 @@ void MinimumVersionPolicyHandler::FetchEolInfo() { ...@@ -272,10 +282,8 @@ void MinimumVersionPolicyHandler::FetchEolInfo() {
return; return;
update_required_time_ = clock_->Now(); update_required_time_ = clock_->Now();
chromeos::UpdateEngineClient* update_engine_client =
chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
// Request the End of Life (Auto Update Expiration) status. // Request the End of Life (Auto Update Expiration) status.
update_engine_client->GetEolInfo( GetUpdateEngineClient()->GetEolInfo(
base::BindOnce(&MinimumVersionPolicyHandler::OnFetchEolInfo, base::BindOnce(&MinimumVersionPolicyHandler::OnFetchEolInfo,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
...@@ -411,8 +419,8 @@ void MinimumVersionPolicyHandler::MaybeShowNotificationOnLogin() { ...@@ -411,8 +419,8 @@ void MinimumVersionPolicyHandler::MaybeShowNotificationOnLogin() {
void MinimumVersionPolicyHandler::MaybeShowNotification( void MinimumVersionPolicyHandler::MaybeShowNotification(
base::TimeDelta warning) { base::TimeDelta warning) {
const NetworkStatus status = GetCurrentNetworkStatus(); const NetworkStatus status = GetCurrentNetworkStatus();
if (status == NetworkStatus::kAllowed || !delegate_->IsUserLoggedIn() || if ((!eol_reached_ && status == NetworkStatus::kAllowed) ||
!delegate_->IsUserManaged()) { !delegate_->IsUserLoggedIn() || !delegate_->IsUserManaged()) {
return; return;
} }
...@@ -421,20 +429,36 @@ void MinimumVersionPolicyHandler::MaybeShowNotification( ...@@ -421,20 +429,36 @@ void MinimumVersionPolicyHandler::MaybeShowNotification(
std::make_unique<chromeos::UpdateRequiredNotification>(); std::make_unique<chromeos::UpdateRequiredNotification>();
} }
if (status == NetworkStatus::kOffline) { NotificationType type = NotificationType::kNoConnection;
notification_handler_->Show( base::OnceClosure button_click_callback;
NotificationType::kNoConnection, warning, GetEnterpriseDomainName(), std::string domain_name = GetEnterpriseDomainName();
base::BindOnce(&OpenNetworkSettings), auto close_callback =
base::BindOnce(&MinimumVersionPolicyHandler::StopObservingNetwork, base::BindOnce(&MinimumVersionPolicyHandler::StopObservingNetwork,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr());
if (eol_reached_) {
type = NotificationType::kEolReached;
button_click_callback = base::BindOnce(&OpenEnterpriseInfoPage);
} else if (status == NetworkStatus::kMetered) {
type = NotificationType::kMeteredConnection;
button_click_callback = base::BindOnce(
&MinimumVersionPolicyHandler::UpdateOverMeteredPermssionGranted,
weak_factory_.GetWeakPtr());
} else if (status == NetworkStatus::kOffline) {
button_click_callback = base::BindOnce(&OpenNetworkSettings);
} else {
NOTREACHED();
return;
}
notification_handler_->Show(type, warning, domain_name,
std::move(button_click_callback),
std::move(close_callback));
if (!eol_reached_) {
chromeos::NetworkStateHandler* network_state_handler =
chromeos::NetworkHandler::Get()->network_state_handler();
if (!network_state_handler->HasObserver(this))
network_state_handler->AddObserver(this, FROM_HERE);
} }
// TODO(https://crbug.com/1048607): Show in-session notifications in case of
// end-of-life and metered network.
chromeos::NetworkStateHandler* network_state_handler =
chromeos::NetworkHandler::Get()->network_state_handler();
if (!network_state_handler->HasObserver(this))
network_state_handler->AddObserver(this, FROM_HERE);
} }
void MinimumVersionPolicyHandler::ShowAndScheduleNotification( void MinimumVersionPolicyHandler::ShowAndScheduleNotification(
...@@ -471,6 +495,7 @@ void MinimumVersionPolicyHandler::ShowAndScheduleNotification( ...@@ -471,6 +495,7 @@ void MinimumVersionPolicyHandler::ShowAndScheduleNotification(
void MinimumVersionPolicyHandler::OnUpdate(const BuildState* build_state) { void MinimumVersionPolicyHandler::OnUpdate(const BuildState* build_state) {
// If the device has been successfully updated, the relaunch notifications // If the device has been successfully updated, the relaunch notifications
// will reboot it for applying the updates. // will reboot it for applying the updates.
GetUpdateEngineClient()->RemoveObserver(this);
if (build_state->update_type() == BuildState::UpdateType::kNormalUpdate) if (build_state->update_type() == BuildState::UpdateType::kNormalUpdate)
ResetOnUpdateCompleted(); ResetOnUpdateCompleted();
} }
...@@ -497,6 +522,42 @@ void MinimumVersionPolicyHandler::StopObservingNetwork() { ...@@ -497,6 +522,42 @@ void MinimumVersionPolicyHandler::StopObservingNetwork() {
network_state_handler->RemoveObserver(this, FROM_HERE); network_state_handler->RemoveObserver(this, FROM_HERE);
} }
void MinimumVersionPolicyHandler::UpdateOverMeteredPermssionGranted() {
chromeos::UpdateEngineClient* const update_engine_client =
GetUpdateEngineClient();
if (!update_engine_client->HasObserver(this))
update_engine_client->AddObserver(this);
update_engine_client->RequestUpdateCheck(
base::BindOnce(&MinimumVersionPolicyHandler::OnUpdateCheckStarted,
weak_factory_.GetWeakPtr()));
}
void MinimumVersionPolicyHandler::OnUpdateCheckStarted(
chromeos::UpdateEngineClient::UpdateCheckResult result) {
if (result != chromeos::UpdateEngineClient::UPDATE_RESULT_SUCCESS)
GetUpdateEngineClient()->RemoveObserver(this);
}
void MinimumVersionPolicyHandler::UpdateStatusChanged(
const update_engine::StatusResult& status) {
if (status.current_operation() ==
update_engine::Operation::NEED_PERMISSION_TO_UPDATE) {
GetUpdateEngineClient()->SetUpdateOverCellularOneTimePermission(
status.new_version(), status.new_size(),
base::BindOnce(&MinimumVersionPolicyHandler::
OnSetUpdateOverCellularOneTimePermission,
weak_factory_.GetWeakPtr()));
}
}
void MinimumVersionPolicyHandler::OnSetUpdateOverCellularOneTimePermission(
bool success) {
if (success)
UpdateOverMeteredPermssionGranted();
else
GetUpdateEngineClient()->RemoveObserver(this);
}
void MinimumVersionPolicyHandler::OnDeadlineReached() { void MinimumVersionPolicyHandler::OnDeadlineReached() {
deadline_reached = true; deadline_reached = true;
if (delegate_->IsLoginSessionState() && !delegate_->IsLoginInProgress()) { if (delegate_->IsLoginSessionState() && !delegate_->IsLoginInProgress()) {
......
...@@ -36,7 +36,8 @@ namespace policy { ...@@ -36,7 +36,8 @@ namespace policy {
// checks if respective requirement is met. // checks if respective requirement is met.
class MinimumVersionPolicyHandler class MinimumVersionPolicyHandler
: public BuildStateObserver, : public BuildStateObserver,
public chromeos::NetworkStateHandlerObserver { public chromeos::NetworkStateHandlerObserver,
public chromeos::UpdateEngineClient::Observer {
public: public:
static const char kChromeVersion[]; static const char kChromeVersion[];
static const char kWarningPeriod[]; static const char kWarningPeriod[];
...@@ -133,6 +134,9 @@ class MinimumVersionPolicyHandler ...@@ -133,6 +134,9 @@ class MinimumVersionPolicyHandler
// NetworkStateHandlerObserver: // NetworkStateHandlerObserver:
void DefaultNetworkChanged(const chromeos::NetworkState* network) override; void DefaultNetworkChanged(const chromeos::NetworkState* network) override;
// UpdateEngineClient::Observer:
void UpdateStatusChanged(const update_engine::StatusResult& status) override;
void AddObserver(Observer* observer); void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer); void RemoveObserver(Observer* observer);
bool RequirementsAreSatisfied() const { return GetState() == nullptr; } bool RequirementsAreSatisfied() const { return GetState() == nullptr; }
...@@ -205,6 +209,17 @@ class MinimumVersionPolicyHandler ...@@ -205,6 +209,17 @@ class MinimumVersionPolicyHandler
void StopObservingNetwork(); void StopObservingNetwork();
// Start updating over metered network as user has given consent through
// notification click.
void UpdateOverMeteredPermssionGranted();
// Tells whether starting an update check succeeded or not.
void OnUpdateCheckStarted(
chromeos::UpdateEngineClient::UpdateCheckResult result);
// Callback from UpdateEngineClient::SetUpdateOverCellularOneTimePermission().
void OnSetUpdateOverCellularOneTimePermission(bool success);
// Updates pref |kUpdateRequiredWarningPeriod| in local state to // Updates pref |kUpdateRequiredWarningPeriod| in local state to
// |warning_time|. If |kUpdateRequiredTimerStartTime| is not null, it means // |warning_time|. If |kUpdateRequiredTimerStartTime| is not null, it means
// update is already required and hence, the timer start time should not be // update is already required and hence, the timer start time should not be
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/time/default_clock.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h" #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
...@@ -41,6 +42,7 @@ const char kNewerVersion[] = "81.5.4"; ...@@ -41,6 +42,7 @@ const char kNewerVersion[] = "81.5.4";
const char kNewestVersion[] = "82"; const char kNewestVersion[] = "82";
const char kOldVersion[] = "78.1.5"; const char kOldVersion[] = "78.1.5";
const char kUpdateRequiredNotificationId[] = "policy.update_required"; const char kUpdateRequiredNotificationId[] = "policy.update_required";
const char kCellularServicePath[] = "/service/cellular1";
const int kLongWarning = 10; const int kLongWarning = 10;
const int kShortWarning = 2; const int kShortWarning = 2;
...@@ -91,6 +93,10 @@ class MinimumVersionPolicyHandlerTest ...@@ -91,6 +93,10 @@ class MinimumVersionPolicyHandlerTest
return notification_service_.get(); return notification_service_.get();
} }
chromeos::FakeUpdateEngineClient* update_engine() {
return fake_update_engine_client_;
}
void SetUserManaged(bool managed) { user_managed_ = managed; } void SetUserManaged(bool managed) { user_managed_ = managed; }
content::BrowserTaskEnvironment task_environment{ content::BrowserTaskEnvironment task_environment{
...@@ -102,6 +108,7 @@ class MinimumVersionPolicyHandlerTest ...@@ -102,6 +108,7 @@ class MinimumVersionPolicyHandlerTest
chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_; chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
std::unique_ptr<NotificationDisplayServiceTester> notification_service_; std::unique_ptr<NotificationDisplayServiceTester> notification_service_;
chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_; chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
chromeos::FakeUpdateEngineClient* fake_update_engine_client_;
std::unique_ptr<base::Version> current_version_; std::unique_ptr<base::Version> current_version_;
std::unique_ptr<MinimumVersionPolicyHandler> minimum_version_policy_handler_; std::unique_ptr<MinimumVersionPolicyHandler> minimum_version_policy_handler_;
}; };
...@@ -112,6 +119,7 @@ MinimumVersionPolicyHandlerTest::MinimumVersionPolicyHandlerTest() ...@@ -112,6 +119,7 @@ MinimumVersionPolicyHandlerTest::MinimumVersionPolicyHandlerTest()
void MinimumVersionPolicyHandlerTest::SetUp() { void MinimumVersionPolicyHandlerTest::SetUp() {
auto fake_update_engine_client = auto fake_update_engine_client =
std::make_unique<chromeos::FakeUpdateEngineClient>(); std::make_unique<chromeos::FakeUpdateEngineClient>();
fake_update_engine_client_ = fake_update_engine_client.get();
chromeos::DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient( chromeos::DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient(
std::move(fake_update_engine_client)); std::move(fake_update_engine_client));
chromeos::NetworkHandler::Initialize(); chromeos::NetworkHandler::Initialize();
...@@ -420,11 +428,129 @@ TEST_F(MinimumVersionPolicyHandlerTest, NoNetworkNotifications) { ...@@ -420,11 +428,129 @@ TEST_F(MinimumVersionPolicyHandlerTest, NoNetworkNotifications) {
base::string16 expected_title_last_day = base::string16 expected_title_last_day =
base::ASCIIToUTF16("Last day to update device"); base::ASCIIToUTF16("Last day to update device");
base::string16 expected_message_last_day = base::ASCIIToUTF16(
"managed.com requires you to download an update today. The "
"update will download automatically when you connect to the internet.");
auto notification_last_day =
display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_long_waiting);
EXPECT_EQ(notification_last_day->title(), expected_title_last_day);
EXPECT_EQ(notification_last_day->message(), expected_message_last_day);
}
TEST_F(MinimumVersionPolicyHandlerTest, MeteredNetworkNotifications) {
// Connect to metered network
chromeos::ShillServiceClient::TestInterface* service_test =
chromeos::DBusThreadManager::Get()
->GetShillServiceClient()
->GetTestInterface();
service_test->ClearServices();
service_test->AddService(kCellularServicePath,
kCellularServicePath /* guid */,
kCellularServicePath, shill::kTypeCellular,
shill::kStateOnline, true /* visible */);
base::RunLoop().RunUntilIdle();
// This is needed to wait till EOL status is fetched from the update_engine.
base::RunLoop run_loop;
GetMinimumVersionPolicyHandler()->set_fetch_eol_callback_for_testing(
run_loop.QuitClosure());
// Create and set pref value to invoke policy handler.
base::Value requirement_list(base::Value::Type::LIST);
requirement_list.Append(
CreateRequirement(kNewVersion, kLongWarning, kLongWarning));
SetPolicyPref(std::move(requirement_list));
run_loop.Run();
EXPECT_TRUE(
GetMinimumVersionPolicyHandler()->IsDeadlineTimerRunningForTesting());
// Check notification is shown for metered network with the warning time.
base::string16 expected_title =
base::ASCIIToUTF16("Update device within 10 days");
base::string16 expected_message = base::ASCIIToUTF16(
"managed.com requires you to connect to Wi-Fi and download an update "
"before the deadline. Or, download from a metered connection (charges "
"may apply).");
auto notification_long_waiting =
display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_long_waiting);
EXPECT_EQ(notification_long_waiting->title(), expected_title);
EXPECT_EQ(notification_long_waiting->message(), expected_message);
// Expire the notification timer to show new notification on the last day.
const base::TimeDelta warning = base::TimeDelta::FromDays(kLongWarning - 1);
task_environment.FastForwardBy(warning);
base::string16 expected_title_last_day =
base::ASCIIToUTF16("Last day to update device");
base::string16 expected_message_last_day = base::ASCIIToUTF16(
"managed.com requires you to connect to Wi-Fi today to download an "
"update. Or, download from a metered connection (charges may apply).");
auto notification_last_day =
display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_long_waiting);
EXPECT_EQ(notification_last_day->title(), expected_title_last_day);
EXPECT_EQ(notification_last_day->message(), expected_message_last_day);
}
TEST_F(MinimumVersionPolicyHandlerTest, EolNotifications) {
// Set device state to end of life.
update_engine()->set_eol_date(base::DefaultClock::GetInstance()->Now() -
base::TimeDelta::FromDays(1));
// This is needed to wait till EOL status is fetched from the update_engine.
base::RunLoop run_loop;
GetMinimumVersionPolicyHandler()->set_fetch_eol_callback_for_testing(
run_loop.QuitClosure());
// Create and set pref value to invoke policy handler.
base::Value requirement_list(base::Value::Type::LIST);
requirement_list.Append(
CreateRequirement(kNewVersion, kLongWarning, kLongWarning));
SetPolicyPref(std::move(requirement_list));
run_loop.Run();
EXPECT_TRUE(
GetMinimumVersionPolicyHandler()->IsDeadlineTimerRunningForTesting());
// Check notification is shown for end of life with the warning time.
base::string16 expected_title =
base::ASCIIToUTF16("Return device within 10 days");
base::string16 expected_message = base::ASCIIToUTF16(
"managed.com requires you to back up your data and return this device "
"before the deadline.");
auto notification_long_waiting =
display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_long_waiting);
EXPECT_EQ(notification_long_waiting->title(), expected_title);
EXPECT_EQ(notification_long_waiting->message(), expected_message);
// Expire notification timer to show new notification a week before deadline.
const base::TimeDelta warning = base::TimeDelta::FromDays(kLongWarning - 7);
task_environment.FastForwardBy(warning);
base::string16 expected_title_one_week =
base::ASCIIToUTF16("Return device within 7 days");
auto notification_one_week =
display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_one_week);
EXPECT_EQ(notification_one_week->title(), expected_title_one_week);
EXPECT_EQ(notification_one_week->message(), expected_message);
// Expire the notification timer to show new notification on the last day.
const base::TimeDelta warning_last_day = base::TimeDelta::FromDays(6);
task_environment.FastForwardBy(warning_last_day);
base::string16 expected_title_last_day =
base::ASCIIToUTF16("Immediate return required");
base::string16 expected_message_last_day = base::ASCIIToUTF16(
"managed.com requires you to back up your data and return this device "
"today.");
auto notification_last_day = auto notification_last_day =
display_service()->GetNotification(kUpdateRequiredNotificationId); display_service()->GetNotification(kUpdateRequiredNotificationId);
ASSERT_TRUE(notification_long_waiting); ASSERT_TRUE(notification_long_waiting);
EXPECT_EQ(notification_last_day->title(), expected_title_last_day); EXPECT_EQ(notification_last_day->title(), expected_title_last_day);
EXPECT_EQ(notification_last_day->message(), expected_message); EXPECT_EQ(notification_last_day->message(), expected_message_last_day);
} }
} // namespace policy } // namespace policy
...@@ -25,27 +25,47 @@ base::string16 GetTitle(NotificationType type, int days_remaining) { ...@@ -25,27 +25,47 @@ base::string16 GetTitle(NotificationType type, int days_remaining) {
// |days_remaining| >= 7. // |days_remaining| >= 7.
switch (type) { switch (type) {
case NotificationType::kNoConnection: case NotificationType::kNoConnection:
return days_remaining > 1
? l10n_util::GetStringFUTF16Int(
IDS_UPDATE_REQUIRED_NO_NETWORK_TITLE_DAYS,
days_remaining)
: l10n_util::GetStringUTF16(
IDS_UPDATE_REQUIRED_NO_NETWORK_TITLE_IMMEDIATE);
case NotificationType::kMeteredConnection: case NotificationType::kMeteredConnection:
return l10n_util::GetPluralStringFUTF16(
IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS, days_remaining);
case NotificationType::kEolReached: case NotificationType::kEolReached:
return base::string16(); return l10n_util::GetPluralStringFUTF16(
IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS, days_remaining);
} }
} }
base::string16 GetMessage(NotificationType type, base::string16 GetMessage(NotificationType type,
const std::string& domain_name) { const std::string& domain_name,
int days_remaining) {
if (days_remaining > 1) {
switch (type) {
case NotificationType::kNoConnection:
return l10n_util::GetStringFUTF16(
IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE,
base::UTF8ToUTF16(domain_name));
case NotificationType::kMeteredConnection:
return l10n_util::GetStringFUTF16(
IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE,
base::UTF8ToUTF16(domain_name));
case NotificationType::kEolReached:
return l10n_util::GetStringFUTF16(IDS_UPDATE_REQUIRED_EOL_MESSAGE,
base::UTF8ToUTF16(domain_name));
}
}
switch (type) { switch (type) {
case NotificationType::kNoConnection: case NotificationType::kNoConnection:
return l10n_util::GetStringFUTF16(IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE, return l10n_util::GetStringFUTF16(
base::UTF8ToUTF16(domain_name)); IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE,
base::UTF8ToUTF16(domain_name));
case NotificationType::kMeteredConnection: case NotificationType::kMeteredConnection:
return l10n_util::GetStringFUTF16(
IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE,
base::UTF8ToUTF16(domain_name));
case NotificationType::kEolReached: case NotificationType::kEolReached:
return base::string16(); return l10n_util::GetStringFUTF16(
IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE,
base::UTF8ToUTF16(domain_name));
} }
} }
...@@ -55,8 +75,10 @@ base::string16 GetButtonText(NotificationType type) { ...@@ -55,8 +75,10 @@ base::string16 GetButtonText(NotificationType type) {
return l10n_util::GetStringUTF16( return l10n_util::GetStringUTF16(
IDS_UPDATE_REQUIRED_SCREEN_OPEN_NETWORK_SETTINGS); IDS_UPDATE_REQUIRED_SCREEN_OPEN_NETWORK_SETTINGS);
case NotificationType::kMeteredConnection: case NotificationType::kMeteredConnection:
return l10n_util::GetStringUTF16(
IDS_UPDATE_REQUIRED_SCREEN_ALLOW_METERED);
case NotificationType::kEolReached: case NotificationType::kEolReached:
return base::string16(); return l10n_util::GetStringUTF16(IDS_UPDATE_REQUIRED_EOL_SEE_DETAILS);
} }
} }
...@@ -89,7 +111,7 @@ void UpdateRequiredNotification::Show(NotificationType type, ...@@ -89,7 +111,7 @@ void UpdateRequiredNotification::Show(NotificationType type,
notification_close_callback_ = std::move(close_callback); notification_close_callback_ = std::move(close_callback);
base::string16 title = GetTitle(type, days_remaining); base::string16 title = GetTitle(type, days_remaining);
base::string16 body = GetMessage(type, domain_name); base::string16 body = GetMessage(type, domain_name, days_remaining);
base::string16 button = GetButtonText(type); base::string16 button = GetButtonText(type);
if (title.empty() || body.empty() || button.empty()) { if (title.empty() || body.empty() || button.empty()) {
NOTREACHED(); NOTREACHED();
......
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