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