1 // Copyright (c) 2013 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 #ifndef UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_
6 #define UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_
7 
8 #include <stddef.h>
9 
10 #include <string>
11 #include <vector>
12 
13 #include "base/memory/ref_counted.h"
14 #include "base/optional.h"
15 #include "base/strings/string16.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "third_party/skia/include/core/SkColor.h"
19 #include "ui/gfx/color_palette.h"
20 #include "ui/gfx/image/image.h"
21 #include "ui/gfx/paint_vector_icon.h"
22 #include "ui/gfx/skia_util.h"
23 #include "ui/gfx/vector_icon_types.h"
24 #include "ui/message_center/public/cpp/message_center_public_export.h"
25 #include "ui/message_center/public/cpp/notification_delegate.h"
26 #include "ui/message_center/public/cpp/notification_types.h"
27 #include "ui/message_center/public/cpp/notifier_id.h"
28 #include "url/gurl.h"
29 
30 namespace gfx {
31 struct VectorIcon;
32 }  // namespace gfx
33 
34 namespace message_center {
35 
36 // Represents an individual item in NOTIFICATION_TYPE_MULTIPLE notifications.
37 struct MESSAGE_CENTER_PUBLIC_EXPORT NotificationItem {
38   base::string16 title;
39   base::string16 message;
40 };
41 
42 enum class SettingsButtonHandler {
43   NONE = 0,      // No button. This is the default. Does not affect native
44                  // settings button (like on Android).
45   INLINE = 1,    // Button shown, settings inline.
46   DELEGATE = 2,  // Button shown, notification's delegate handles action.
47 };
48 
49 enum class SystemNotificationWarningLevel { NORMAL, WARNING, CRITICAL_WARNING };
50 
51 // Represents a button to be shown as part of a notification.
52 struct MESSAGE_CENTER_PUBLIC_EXPORT ButtonInfo {
53   explicit ButtonInfo(const base::string16& title);
54   ButtonInfo(const ButtonInfo& other);
55   ButtonInfo();
56   ~ButtonInfo();
57   ButtonInfo& operator=(const ButtonInfo& other);
58 
59   // Title that should be displayed on the notification button.
60   base::string16 title;
61 
62   // Icon that should be displayed on the notification button. Optional. On some
63   // platforms, a mask will be applied to the icon, to match the visual
64   // requirements of the notification. As with Android, MD notifications don't
65   // display this icon.
66   gfx::Image icon;
67 
68   // The placeholder string that should be displayed in the input field for
69   // text input type buttons until the user has entered a response themselves.
70   // If the value is null, there is no input field associated with the button.
71   base::Optional<base::string16> placeholder;
72 };
73 
74 enum class FullscreenVisibility {
75   NONE = 0,       // Don't show the notification over fullscreen (default).
76   OVER_USER = 1,  // Show over the current fullscreened client window.
77                   // windows (like Chrome OS login).
78 };
79 
80 // Represents rich features available for notifications.
81 class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData {
82  public:
83   RichNotificationData();
84   RichNotificationData(const RichNotificationData& other);
85   ~RichNotificationData();
86 
87   // Priority of the notification. This must be one of the NotificationPriority
88   // values defined in notification_types.h.
89   int priority = DEFAULT_PRIORITY;
90 
91   // Whether the notification should remain on screen indefinitely.
92   bool never_timeout = false;
93 
94   // Time indicating when the notification was shown. Defaults to the time at
95   // which the RichNotificationData instance is constructed.
96   base::Time timestamp;
97 
98   // Context message to display below the notification's content. Optional. May
99   // not be used for notifications that have an explicit origin URL set.
100   base::string16 context_message;
101 
102   // Large image to display on the notification. Optional.
103   gfx::Image image;
104 
105   // Small badge to display on the notification to illustrate the source of the
106   // notification. Optional.
107   gfx::Image small_image;
108 
109   // Vector version of |small_image|.
110   // Used by Notification::GenerateMaskedSmallIcon.
111   // If not available, |small_image| will be used by the method. Optional.
112   //
113   // Due to the restriction of CreateVectorIcon, this should be a pointer to
114   // globally defined VectorIcon instance e.g. kNotificationCapsLockIcon.
115   // gfx::Image created by gfx::CreateVectorIcon internally stores reference to
116   // VectorIcon, so the VectorIcon should live longer than gfx::Image instance.
117   // As a temporary solution to this problem, we make this variable a pointer
118   // and only pass globally defined constants.
119   // TODO(tetsui): Remove the pointer, after fixing VectorIconSource not to
120   // retain VectorIcon reference.  https://crbug.com/760866
121   const gfx::VectorIcon* vector_small_image = &gfx::kNoneIcon;
122 
123   // Items to display on the notification. Only applicable for notifications
124   // that have type NOTIFICATION_TYPE_MULTIPLE.
125   std::vector<NotificationItem> items;
126 
127   // Progress, in range of [0-100], of NOTIFICATION_TYPE_PROGRESS notifications.
128   // Values outside of the range (e.g. -1) will show an infinite loading
129   // progress bar.
130   int progress = 0;
131 
132   // Status text string shown in NOTIFICATION_TYPE_PROGRESS notifications.
133   // If MD style notification is not enabled, this attribute is ignored.
134   base::string16 progress_status;
135 
136   // Buttons that should show up on the notification. A maximum of 16 buttons
137   // is supported by the current implementation, but this may differ between
138   // platforms.
139   std::vector<ButtonInfo> buttons;
140 
141   // Whether updates to the visible notification should be announced to users
142   // depending on visual assistance systems.
143   bool should_make_spoken_feedback_for_popup_updates = true;
144 
145 #if defined(OS_CHROMEOS)
146   // Flag if the notification is pinned. If true, the notification is pinned
147   // and the user can't remove it.
148   bool pinned = false;
149 #endif  // defined(OS_CHROMEOS)
150 
151   // Vibration pattern to play when displaying the notification. There must be
152   // an odd number of entries in this pattern when it's set: numbers of
153   // milliseconds to vibrate separated by numbers of milliseconds to pause.
154   std::vector<int> vibration_pattern;
155 
156   // Whether the vibration pattern and other applicable announcement mechanisms
157   // should be considered when updating the notification.
158   bool renotify = false;
159 
160   // Whether all announcement mechansims should be suppressed when displaying
161   // the notification.
162   bool silent = false;
163 
164   // An accessible description of the notification's contents.
165   base::string16 accessible_name;
166 
167   // Unified theme color used in new style notification.
168   // Usually, it should not be set directly.
169   // For system notification, ash::CreateSystemNotification with
170   // SystemNotificationWarningLevel should be used.
171   SkColor accent_color = SK_ColorTRANSPARENT;
172 
173   // Controls whether a settings button should appear on the notification. See
174   // enum definition. TODO(estade): turn this into a boolean. See
175   // crbug.com/780342
176   SettingsButtonHandler settings_button_handler = SettingsButtonHandler::NONE;
177 
178   // Controls whether a snooze button should appear on the notification.
179   bool should_show_snooze_button = false;
180 
181   FullscreenVisibility fullscreen_visibility = FullscreenVisibility::NONE;
182 };
183 
184 class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
185  public:
186   // Creates a new notification.
187   //
188   // |type|: Type of the notification that dictates the layout.
189   // |id|: Identifier of the notification. Showing a notification that shares
190   //       its profile and identifier with an already visible notification will
191   //       replace the former one
192   // |title|: Title of the notification.
193   // |message|: Body text of the notification. May not be used for certain
194   //            values of |type|, for example list-style notifications.
195   // |icon|: Icon to show alongside of the notification.
196   // |display_source|: Textual representation of who's shown the notification.
197   // |origin_url|: URL of the website responsible for showing the notification.
198   // |notifier_id|: NotifierId instance representing the system responsible for
199   //                showing the notification.
200   // |optional_fields|: Rich data that can be used to assign more elaborate
201   //                    features to notifications.
202   // |delegate|: Delegate that will influence the behaviour of this notification
203   //             and receives events on its behalf. May be omitted.
204   Notification(NotificationType type,
205                const std::string& id,
206                const base::string16& title,
207                const base::string16& message,
208                const gfx::Image& icon,
209                const base::string16& display_source,
210                const GURL& origin_url,
211                const NotifierId& notifier_id,
212                const RichNotificationData& optional_fields,
213                scoped_refptr<NotificationDelegate> delegate);
214 
215   // Creates a copy of the |other| notification. The delegate, if any, will be
216   // identical for both the Notification instances. The |id| of the notification
217   // will be replaced by the given value.
218   Notification(const std::string& id, const Notification& other);
219 
220   // Creates a copy of the |other| notification. The delegate will be replaced
221   // by |delegate|.
222   Notification(scoped_refptr<NotificationDelegate> delegate,
223                const Notification& other);
224 
225   // Creates a copy of the |other| notification. The delegate, if any, will be
226   // identical for both the Notification instances.
227   Notification(const Notification& other);
228 
229   Notification& operator=(const Notification& other);
230 
231   virtual ~Notification();
232 
233   // Performs a deep copy of |notification|, including images and (optionally)
234   // the body image, small image, and icon images which are not supported on all
235   // platforms.
236   static std::unique_ptr<Notification> DeepCopy(
237       const Notification& notification,
238       bool include_body_image,
239       bool include_small_image,
240       bool include_icon_images);
241 
type()242   NotificationType type() const { return type_; }
set_type(NotificationType type)243   void set_type(NotificationType type) { type_ = type; }
244 
245   // Uniquely identifies a notification in the message center. For
246   // notification front ends that support multiple profiles, this id should
247   // identify a unique profile + frontend_notification_id combination. You can
248   // Use this id against the MessageCenter interface but not the
249   // NotificationUIManager interface.
id()250   const std::string& id() const { return id_; }
251 
title()252   const base::string16& title() const { return title_; }
set_title(const base::string16 & title)253   void set_title(const base::string16& title) { title_ = title; }
254 
message()255   const base::string16& message() const { return message_; }
set_message(const base::string16 & message)256   void set_message(const base::string16& message) { message_ = message; }
257 
258   // The origin URL of the script which requested the notification.
259   // Can be empty if the notification is requested by an extension or
260   // Chrome app.
origin_url()261   const GURL& origin_url() const { return origin_url_; }
set_origin_url(const GURL & origin_url)262   void set_origin_url(const GURL& origin_url) { origin_url_ = origin_url; }
263 
264   // A display string for the source of the notification.
display_source()265   const base::string16& display_source() const { return display_source_; }
266 
notifier_id()267   const NotifierId& notifier_id() const { return notifier_id_; }
268 
set_profile_id(const std::string & profile_id)269   void set_profile_id(const std::string& profile_id) {
270     notifier_id_.profile_id = profile_id;
271   }
272 
273   // Begin unpacked values from optional_fields.
priority()274   int priority() const { return optional_fields_.priority; }
set_priority(int priority)275   void set_priority(int priority) { optional_fields_.priority = priority; }
276 
277   // This vibration_pattern property currently has no effect on
278   // non-Android platforms.
vibration_pattern()279   const std::vector<int>& vibration_pattern() const {
280     return optional_fields_.vibration_pattern;
281   }
set_vibration_pattern(const std::vector<int> & vibration_pattern)282   void set_vibration_pattern(const std::vector<int>& vibration_pattern) {
283     optional_fields_.vibration_pattern = vibration_pattern;
284   }
285 
286   // This property currently only works in platforms that support native
287   // notifications.
288   // It determines whether the sound and vibration effects should signal
289   // if the notification is replacing another notification.
renotify()290   bool renotify() const { return optional_fields_.renotify; }
set_renotify(bool renotify)291   void set_renotify(bool renotify) { optional_fields_.renotify = renotify; }
292 
293   // This property currently has no effect on non-Android platforms.
silent()294   bool silent() const { return optional_fields_.silent; }
set_silent(bool silent)295   void set_silent(bool silent) { optional_fields_.silent = silent; }
296 
timestamp()297   base::Time timestamp() const { return optional_fields_.timestamp; }
set_timestamp(const base::Time & timestamp)298   void set_timestamp(const base::Time& timestamp) {
299     optional_fields_.timestamp = timestamp;
300   }
301 
context_message()302   const base::string16 context_message() const {
303     return optional_fields_.context_message;
304   }
305 
set_context_message(const base::string16 & context_message)306   void set_context_message(const base::string16& context_message) {
307     optional_fields_.context_message = context_message;
308   }
309 
310   // Decides if the notification origin should be used as a context message
311   bool UseOriginAsContextMessage() const;
312 
items()313   const std::vector<NotificationItem>& items() const {
314     return optional_fields_.items;
315   }
set_items(const std::vector<NotificationItem> & items)316   void set_items(const std::vector<NotificationItem>& items) {
317     optional_fields_.items = items;
318   }
319 
progress()320   int progress() const { return optional_fields_.progress; }
set_progress(int progress)321   void set_progress(int progress) { optional_fields_.progress = progress; }
322 
progress_status()323   base::string16 progress_status() const {
324     return optional_fields_.progress_status;
325   }
set_progress_status(const base::string16 & progress_status)326   void set_progress_status(const base::string16& progress_status) {
327     optional_fields_.progress_status = progress_status;
328   }
329 
330   // End unpacked values.
331 
332   // Images fetched asynchronously.
icon()333   const gfx::Image& icon() const { return icon_; }
set_icon(const gfx::Image & icon)334   void set_icon(const gfx::Image& icon) { icon_ = icon; }
335 
image()336   const gfx::Image& image() const { return optional_fields_.image; }
set_image(const gfx::Image & image)337   void set_image(const gfx::Image& image) { optional_fields_.image = image; }
338 
small_image()339   const gfx::Image& small_image() const { return optional_fields_.small_image; }
set_small_image(const gfx::Image & image)340   void set_small_image(const gfx::Image& image) {
341     optional_fields_.small_image = image;
342   }
343 
vector_small_image()344   const gfx::VectorIcon& vector_small_image() const {
345     return *optional_fields_.vector_small_image;
346   }
347   // Due to the restriction of CreateVectorIcon, this should be a pointer to
348   // globally defined VectorIcon instance e.g. kNotificationCapsLockIcon.
349   // See detailed comment in RichNotificationData::vector_small_image.
set_vector_small_image(const gfx::VectorIcon & image)350   void set_vector_small_image(const gfx::VectorIcon& image) {
351     optional_fields_.vector_small_image = &image;
352   }
353 
354   // Mask the color of |small_image| to the given |color|.
355   // If |vector_small_image| is available, it returns the vector image
356   // filled by the |color|.
357   // Otherwise, it uses alpha channel of the rasterized |small_image| for
358   // masking.
359   gfx::Image GenerateMaskedSmallIcon(int dip_size, SkColor color) const;
360 
361   // Buttons, with icons fetched asynchronously.
buttons()362   const std::vector<ButtonInfo>& buttons() const {
363     return optional_fields_.buttons;
364   }
set_buttons(const std::vector<ButtonInfo> & buttons)365   void set_buttons(const std::vector<ButtonInfo>& buttons) {
366     optional_fields_.buttons = buttons;
367   }
368   void SetButtonIcon(size_t index, const gfx::Image& icon);
369 
370   // Used to keep the order of notifications with the same timestamp.
371   // The notification with lesser serial_number is considered 'older'.
serial_number()372   unsigned serial_number() { return serial_number_; }
373 
374   // Gets and sets whether the notifiction should remain onscreen permanently.
never_timeout()375   bool never_timeout() const { return optional_fields_.never_timeout; }
set_never_timeout(bool never_timeout)376   void set_never_timeout(bool never_timeout) {
377     optional_fields_.never_timeout = never_timeout;
378   }
379 
pinned()380   bool pinned() const {
381 #if defined(OS_CHROMEOS)
382     return optional_fields_.pinned;
383 #else
384     return false;
385 #endif  // defined(OS_CHROMEOS)
386   }
387 #if defined(OS_CHROMEOS)
set_pinned(bool pinned)388   void set_pinned(bool pinned) { optional_fields_.pinned = pinned; }
389 #endif  // defined(OS_CHROMEOS)
390 
391   // Gets a text for spoken feedback.
accessible_name()392   const base::string16& accessible_name() const {
393     return optional_fields_.accessible_name;
394   }
395 
accent_color()396   SkColor accent_color() const { return optional_fields_.accent_color; }
set_accent_color(SkColor accent_color)397   void set_accent_color(SkColor accent_color) {
398     optional_fields_.accent_color = accent_color;
399   }
400 
should_show_settings_button()401   bool should_show_settings_button() const {
402     return optional_fields_.settings_button_handler !=
403            SettingsButtonHandler::NONE;
404   }
405 
set_settings_button_handler(SettingsButtonHandler handler)406   void set_settings_button_handler(SettingsButtonHandler handler) {
407     optional_fields_.settings_button_handler = handler;
408   }
409 
should_show_snooze_button()410   bool should_show_snooze_button() const {
411     return optional_fields_.should_show_snooze_button;
412   }
413 
fullscreen_visibility()414   FullscreenVisibility fullscreen_visibility() const {
415     return optional_fields_.fullscreen_visibility;
416   }
set_fullscreen_visibility(FullscreenVisibility visibility)417   void set_fullscreen_visibility(FullscreenVisibility visibility) {
418     optional_fields_.fullscreen_visibility = visibility;
419   }
420 
delegate()421   NotificationDelegate* delegate() const { return delegate_.get(); }
422 
rich_notification_data()423   const RichNotificationData& rich_notification_data() const {
424     return optional_fields_;
425   }
426 
set_delegate(scoped_refptr<NotificationDelegate> delegate)427   void set_delegate(scoped_refptr<NotificationDelegate> delegate) {
428     DCHECK(!delegate_);
429     delegate_ = delegate;
430   }
431 
432   // Set the priority to SYSTEM. The system priority user needs to call this
433   // method explicitly, to avoid setting it accidentally.
434   void SetSystemPriority();
435 
custom_view_type()436   const std::string& custom_view_type() const { return custom_view_type_; }
set_custom_view_type(const std::string & custom_view_type)437   void set_custom_view_type(const std::string& custom_view_type) {
438     DCHECK_EQ(type(), NotificationType::NOTIFICATION_TYPE_CUSTOM);
439     custom_view_type_ = custom_view_type;
440   }
441 
442  protected:
443   // The type of notification we'd like displayed.
444   NotificationType type_;
445 
446   std::string id_;
447   base::string16 title_;
448   base::string16 message_;
449 
450   // Image data for the associated icon, used by Ash when available.
451   gfx::Image icon_;
452 
453   // The display string for the source of the notification.  Could be
454   // the same as |origin_url_|, or the name of an extension.
455   // Expected to be a localized user facing string.
456   base::string16 display_source_;
457 
458  private:
459   // The origin URL of the script which requested the notification.
460   // Can be empty if requested through a chrome app or extension or if
461   // it's a system notification.
462   GURL origin_url_;
463   NotifierId notifier_id_;
464   RichNotificationData optional_fields_;
465 
466   // TODO(estade): these book-keeping fields should be moved into
467   // NotificationList.
468   unsigned serial_number_;
469 
470   // A proxy object that allows access back to the JavaScript object that
471   // represents the notification, for firing events.
472   scoped_refptr<NotificationDelegate> delegate_;
473 
474   // For custom notifications this determines which factory will be used for
475   // creating the view for this notification. The type should match the type
476   // used to register the factory in MessageViewFactory.
477   std::string custom_view_type_;
478 };
479 
480 }  // namespace message_center
481 
482 #endif  // UI_MESSAGE_CENTER_PUBLIC_CPP_NOTIFICATION_H_
483