1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/child_accounts/time_limit_notifier.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "ash/public/cpp/notification_utils.h"
11 #include "base/bind.h"
12 #include "base/i18n/time_formatting.h"
13 #include "base/memory/ref_counted.h"
14 #include "chrome/browser/notifications/notification_display_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "chromeos/ui/vector_icons/vector_icons.h"
18 #include "content/public/browser/browser_context.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/l10n/time_format.h"
21 #include "ui/message_center/public/cpp/notification.h"
22 #include "url/gurl.h"
23
24 namespace chromeos {
25
26 namespace {
27
28 constexpr base::TimeDelta kWarningNotificationTimeout =
29 base::TimeDelta::FromMinutes(5);
30 constexpr base::TimeDelta kExitNotificationTimeout =
31 base::TimeDelta::FromMinutes(1);
32
33 // Lock notification id. All the time limit lock notifications share the same id
34 // so that a subsequent notification can replace the previous one.
35 constexpr char kTimeLimitLockNotificationId[] = "time-limit-lock-notification";
36
37 // Policy update notification id. Each limit has its own id, because we want to
38 // display all updates, which may happen simultaneously.
39 constexpr char kTimeLimitBedtimeUpdatedId[] = "time-limit-bedtime-updated";
40 constexpr char kTimeLimitScreenTimeUpdatedId[] =
41 "time-limit-screen-time-updated";
42 constexpr char kTimeLimitOverrideUpdatedId[] = "time-limit-override-updated";
43
44 // The notifier id representing the app.
45 constexpr char kTimeLimitNotifierId[] = "family-link";
46
ShowNotification(base::string16 title,base::string16 message,const std::string & notification_id,content::BrowserContext * context)47 void ShowNotification(base::string16 title,
48 base::string16 message,
49 const std::string& notification_id,
50 content::BrowserContext* context) {
51 message_center::RichNotificationData option_fields;
52 option_fields.fullscreen_visibility =
53 message_center::FullscreenVisibility::OVER_USER;
54 std::unique_ptr<message_center::Notification> notification =
55 ash::CreateSystemNotification(
56 message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
57 message,
58 l10n_util::GetStringUTF16(IDS_TIME_LIMIT_NOTIFICATION_DISPLAY_SOURCE),
59 GURL(),
60 message_center::NotifierId(
61 message_center::NotifierType::SYSTEM_COMPONENT,
62 kTimeLimitNotifierId),
63 option_fields,
64 base::MakeRefCounted<message_center::NotificationDelegate>(),
65 chromeos::kNotificationSupervisedUserIcon,
66 message_center::SystemNotificationWarningLevel::NORMAL);
67 NotificationDisplayService::GetForProfile(
68 Profile::FromBrowserContext(context))
69 ->Display(NotificationHandler::Type::TRANSIENT, *notification,
70 /*metadata=*/nullptr);
71 }
72
RemainingTimeString(base::TimeDelta time_remaining)73 base::string16 RemainingTimeString(base::TimeDelta time_remaining) {
74 return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
75 ui::TimeFormat::LENGTH_LONG, time_remaining);
76 }
77
78 } // namespace
79
TimeLimitNotifier(content::BrowserContext * context)80 TimeLimitNotifier::TimeLimitNotifier(content::BrowserContext* context)
81 : TimeLimitNotifier(context, nullptr /* task_runner */) {}
82
83 TimeLimitNotifier::~TimeLimitNotifier() = default;
84
MaybeScheduleLockNotifications(LimitType limit_type,base::TimeDelta remaining_time)85 void TimeLimitNotifier::MaybeScheduleLockNotifications(
86 LimitType limit_type,
87 base::TimeDelta remaining_time) {
88 // Stop any previously set timers.
89 UnscheduleNotifications();
90
91 int title_id;
92 switch (limit_type) {
93 case LimitType::kScreenTime:
94 title_id = IDS_SCREEN_TIME_NOTIFICATION_TITLE;
95 break;
96 case LimitType::kBedTime:
97 case LimitType::kOverride:
98 title_id = IDS_BED_TIME_NOTIFICATION_TITLE;
99 break;
100 }
101
102 const base::string16 title = l10n_util::GetStringUTF16(title_id);
103
104 if (remaining_time >= kWarningNotificationTimeout) {
105 warning_notification_timer_.Start(
106 FROM_HERE, remaining_time - kWarningNotificationTimeout,
107 base::BindOnce(&ShowNotification, title,
108 RemainingTimeString(kWarningNotificationTimeout),
109 kTimeLimitLockNotificationId, context_));
110 }
111 if (remaining_time >= kExitNotificationTimeout) {
112 exit_notification_timer_.Start(
113 FROM_HERE, remaining_time - kExitNotificationTimeout,
114 base::BindOnce(&ShowNotification, title,
115 RemainingTimeString(kExitNotificationTimeout),
116 kTimeLimitLockNotificationId, context_));
117 }
118 }
119
ShowPolicyUpdateNotification(LimitType limit_type,base::Optional<base::Time> lock_time)120 void TimeLimitNotifier::ShowPolicyUpdateNotification(
121 LimitType limit_type,
122 base::Optional<base::Time> lock_time) {
123 int title_id;
124 base::string16 message;
125 std::string notification_id;
126 switch (limit_type) {
127 case LimitType::kScreenTime:
128 title_id = IDS_TIME_LIMIT_UPDATED_NOTIFICATION_TITLE;
129 message = l10n_util::GetStringUTF16(
130 IDS_SCREEN_TIME_UPDATED_NOTIFICATION_MESSAGE);
131 notification_id = kTimeLimitScreenTimeUpdatedId;
132 break;
133 case LimitType::kBedTime:
134 title_id = IDS_TIME_LIMIT_UPDATED_NOTIFICATION_TITLE;
135 message =
136 l10n_util::GetStringUTF16(IDS_BEDTIME_UPDATED_NOTIFICATION_MESSAGE);
137 notification_id = kTimeLimitBedtimeUpdatedId;
138 break;
139 case LimitType::kOverride:
140 if (!lock_time)
141 return;
142 title_id = IDS_OVERRIDE_WITH_DURATION_UPDATED_NOTIFICATION_TITLE;
143 message = l10n_util::GetStringFUTF16(
144 IDS_OVERRIDE_WITH_DURATION_UPDATED_NOTIFICATION_MESSAGE,
145 base::TimeFormatTimeOfDay(lock_time.value()));
146 notification_id = kTimeLimitOverrideUpdatedId;
147 break;
148 }
149 ShowNotification(l10n_util::GetStringUTF16(title_id), message,
150 notification_id, context_);
151 }
152
UnscheduleNotifications()153 void TimeLimitNotifier::UnscheduleNotifications() {
154 // TODO(crbug.com/897975): Stop() should be sufficient, but doesn't have the
155 // expected effect in tests.
156 warning_notification_timer_.AbandonAndStop();
157 exit_notification_timer_.AbandonAndStop();
158 }
159
TimeLimitNotifier(content::BrowserContext * context,scoped_refptr<base::SequencedTaskRunner> task_runner)160 TimeLimitNotifier::TimeLimitNotifier(
161 content::BrowserContext* context,
162 scoped_refptr<base::SequencedTaskRunner> task_runner)
163 : context_(context) {
164 if (task_runner.get()) {
165 warning_notification_timer_.SetTaskRunner(task_runner);
166 exit_notification_timer_.SetTaskRunner(task_runner);
167 }
168 }
169
170 } // namespace chromeos
171