1 // Copyright (c) 2012 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_VIEWS_NOTIFICATION_VIEW_MD_H_
6 #define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_MD_H_
7 
8 #include <vector>
9 
10 #include "base/gtest_prod_util.h"
11 #include "base/macros.h"
12 #include "base/optional.h"
13 #include "base/time/time.h"
14 #include "ui/message_center/message_center_export.h"
15 #include "ui/message_center/views/message_view.h"
16 #include "ui/views/animation/ink_drop_observer.h"
17 #include "ui/views/controls/button/button.h"
18 #include "ui/views/controls/button/label_button.h"
19 #include "ui/views/controls/textfield/textfield_controller.h"
20 
21 namespace views {
22 class ImageButton;
23 class Label;
24 class LabelButton;
25 class ProgressBar;
26 class RadioButton;
27 class Textfield;
28 }
29 
30 namespace message_center {
31 
32 class NotificationHeaderView;
33 class ProportionalImageView;
34 
35 // CompactTitleMessageView shows notification title and message in a single
36 // line. This view is used for NOTIFICATION_TYPE_PROGRESS.
37 class CompactTitleMessageView : public views::View {
38  public:
39   explicit CompactTitleMessageView();
40   ~CompactTitleMessageView() override;
41 
42   const char* GetClassName() const override;
43 
44   gfx::Size CalculatePreferredSize() const override;
45   void Layout() override;
46 
47   void set_title(const base::string16& title);
48   void set_message(const base::string16& message);
49 
50  private:
51   DISALLOW_COPY_AND_ASSIGN(CompactTitleMessageView);
52 
53   views::Label* title_ = nullptr;
54   views::Label* message_ = nullptr;
55 };
56 
57 class LargeImageView : public views::View {
58  public:
59   LargeImageView();
60   ~LargeImageView() override;
61 
62   void SetImage(const gfx::ImageSkia& image);
63 
64   void OnPaint(gfx::Canvas* canvas) override;
65   const char* GetClassName() const override;
66 
67  private:
68   gfx::Size GetResizedImageSize();
69 
70   gfx::ImageSkia image_;
71 
72   DISALLOW_COPY_AND_ASSIGN(LargeImageView);
73 };
74 
75 // This class is needed in addition to LabelButton mainly becuase we want to set
76 // visible_opacity of InkDropHighlight.
77 // This button capitalizes the given label string.
78 class NotificationButtonMD : public views::LabelButton {
79  public:
80   // |is_inline_reply| is true when the notification action takes text as the
81   // return value i.e. the notification action is inline reply.
82   // The input field would be shown when the button is clicked.
83   // |placeholder| is placeholder text shown on the input field. Only used when
84   // |is_inline_reply| is true.
85   NotificationButtonMD(views::ButtonListener* listener,
86                        const base::string16& label,
87                        const base::Optional<base::string16>& placeholder);
88   ~NotificationButtonMD() override;
89 
90   void SetText(const base::string16& text) override;
91   const char* GetClassName() const override;
92 
93   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
94       const override;
95 
enabled_color_for_testing()96   SkColor enabled_color_for_testing() { return label()->GetEnabledColor(); }
97 
placeholder()98   const base::Optional<base::string16>& placeholder() const {
99     return placeholder_;
100   }
set_placeholder(const base::Optional<base::string16> & placeholder)101   void set_placeholder(const base::Optional<base::string16>& placeholder) {
102     placeholder_ = placeholder;
103   }
104 
105  private:
106   base::Optional<base::string16> placeholder_;
107 
108   DISALLOW_COPY_AND_ASSIGN(NotificationButtonMD);
109 };
110 
111 class NotificationInputDelegate {
112  public:
113   virtual void OnNotificationInputSubmit(size_t index,
114                                          const base::string16& text) = 0;
115   virtual ~NotificationInputDelegate() = default;
116 };
117 
118 class NotificationInputContainerMD : public views::InkDropHostView,
119                                      public views::ButtonListener,
120                                      public views::TextfieldController {
121  public:
122   NotificationInputContainerMD(NotificationInputDelegate* delegate);
123   ~NotificationInputContainerMD() override;
124 
125   void AnimateBackground(const ui::Event& event);
126 
127   // views::InkDropHostView:
128   void AddLayerBeneathView(ui::Layer* layer) override;
129   void RemoveLayerBeneathView(ui::Layer* layer) override;
130   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
131   SkColor GetInkDropBaseColor() const override;
132 
133   // Overridden from views::TextfieldController:
134   bool HandleKeyEvent(views::Textfield* sender,
135                       const ui::KeyEvent& key_event) override;
136   void OnAfterUserAction(views::Textfield* sender) override;
137 
138   // Overridden from views::ButtonListener:
139   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
140 
textfield()141   views::Textfield* textfield() const { return textfield_; }
button()142   views::ImageButton* button() const { return button_; }
143 
144  private:
145   NotificationInputDelegate* const delegate_;
146 
147   views::InkDropContainerView* const ink_drop_container_;
148 
149   views::Textfield* const textfield_;
150   views::ImageButton* const button_;
151 
152   DISALLOW_COPY_AND_ASSIGN(NotificationInputContainerMD);
153 };
154 
155 // View that displays all current types of notification (web, basic, image, and
156 // list) except the custom notification. Future notification types may be
157 // handled by other classes, in which case instances of those classes would be
158 // returned by the Create() factory method below.
159 class MESSAGE_CENTER_EXPORT NotificationViewMD
160     : public MessageView,
161       public views::InkDropObserver,
162       public NotificationInputDelegate,
163       public views::ButtonListener {
164  public:
165   explicit NotificationViewMD(const Notification& notification);
166   ~NotificationViewMD() override;
167 
168   void Activate();
169 
170   void AddBackgroundAnimation(const ui::Event& event);
171   void RemoveBackgroundAnimation();
172 
173   // MessageView:
174   void AddLayerBeneathView(ui::Layer* layer) override;
175   void RemoveLayerBeneathView(ui::Layer* layer) override;
176   void Layout() override;
177   void OnFocus() override;
178   bool OnMousePressed(const ui::MouseEvent& event) override;
179   bool OnMouseDragged(const ui::MouseEvent& event) override;
180   void OnMouseReleased(const ui::MouseEvent& event) override;
181   void OnMouseEvent(ui::MouseEvent* event) override;
182   void OnGestureEvent(ui::GestureEvent* event) override;
183   void PreferredSizeChanged() override;
184   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
185   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
186   std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
187   SkColor GetInkDropBaseColor() const override;
188   void UpdateWithNotification(const Notification& notification) override;
189   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
190   void UpdateCornerRadius(int top_radius, int bottom_radius) override;
191   NotificationControlButtonsView* GetControlButtonsView() const override;
192   bool IsExpanded() const override;
193   void SetExpanded(bool expanded) override;
194   bool IsManuallyExpandedOrCollapsed() const override;
195   void SetManuallyExpandedOrCollapsed(bool value) override;
196   void OnSettingsButtonPressed(const ui::Event& event) override;
197 
198   // views::InkDropObserver:
199   void InkDropAnimationStarted() override;
200   void InkDropRippleAnimationEnded(views::InkDropState ink_drop_state) override;
201 
202   // Overridden from NotificationInputDelegate:
203   void OnNotificationInputSubmit(size_t index,
204                                  const base::string16& text) override;
205 
206  private:
207   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameExtension);
208   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameSystemNotification);
209   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameWebNotification);
210   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, CreateOrUpdateTest);
211   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage);
212   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
213   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
214                            InlineSettingsInkDropAnimation);
215   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, NotificationWithoutIcon);
216   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ShowProgress);
217   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ShowTimestamp);
218   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor);
219   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestActionButtonClick);
220   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestClick);
221   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestClickExpanded);
222   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
223                            TestDeleteOnDisableNotification);
224   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestDeleteOnToggleExpanded);
225   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing);
226   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestInlineReply);
227   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
228                            TestInlineReplyActivateWithKeyPress);
229   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
230                            TestInlineReplyRemovedByUpdate);
231   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestLongTitleAndMessage);
232   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateAddingIcon);
233   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonCountTest);
234   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonsStateTest);
235   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateInSettings);
236   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateType);
237   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateViewsOrderingTest);
238   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon);
239 
240   friend class NotificationViewMDTest;
241 
242   class NotificationViewMDPathGenerator;
243 
244   void UpdateControlButtonsVisibilityWithNotification(
245       const Notification& notification);
246 
247   void CreateOrUpdateViews(const Notification& notification);
248 
249   void CreateOrUpdateContextTitleView(const Notification& notification);
250   void CreateOrUpdateTitleView(const Notification& notification);
251   void CreateOrUpdateMessageView(const Notification& notification);
252   void CreateOrUpdateCompactTitleMessageView(const Notification& notification);
253   void CreateOrUpdateProgressBarView(const Notification& notification);
254   void CreateOrUpdateProgressStatusView(const Notification& notification);
255   void CreateOrUpdateListItemViews(const Notification& notification);
256   void CreateOrUpdateIconView(const Notification& notification);
257   void CreateOrUpdateSmallIconView(const Notification& notification);
258   void CreateOrUpdateImageView(const Notification& notification);
259   void CreateOrUpdateActionButtonViews(const Notification& notification);
260   void CreateOrUpdateInlineSettingsViews(const Notification& notification);
261 
262   bool IsExpandable();
263   void ToggleExpanded();
264   void UpdateViewForExpandedState(bool expanded);
265   void ToggleInlineSettings(const ui::Event& event);
266 
267   // Returns the list of children which need to have their layers created or
268   // destroyed when the ink drop is visible.
269   std::vector<views::View*> GetChildrenForLayerAdjustment() const;
270 
271   views::InkDropContainerView* const ink_drop_container_;
272 
273   // View containing close and settings buttons
274   std::unique_ptr<NotificationControlButtonsView> control_buttons_view_;
275 
276   // Whether this notification is expanded or not.
277   bool expanded_ = false;
278 
279   // True if the notification is expanded/collapsed by user interaction.
280   // If true, MessagePopupCollection will not auto-collapse the notification.
281   bool manually_expanded_or_collapsed_ = false;
282 
283   // Whether hiding icon on the right side when expanded.
284   bool hide_icon_on_expanded_ = false;
285 
286   // Number of total list items in the given Notification class.
287   int list_items_count_ = 0;
288 
289   // Describes whether the view should display a hand pointer or not.
290   bool clickable_;
291 
292   // Container views directly attached to this view.
293   NotificationHeaderView* header_row_ = nullptr;
294   views::View* content_row_ = nullptr;
295   views::View* actions_row_ = nullptr;
296   views::View* settings_row_ = nullptr;
297 
298   // Containers for left and right side on |content_row_|
299   views::View* left_content_ = nullptr;
300   views::View* right_content_ = nullptr;
301 
302   // Views which are dynamically created inside view hierarchy.
303   views::Label* title_view_ = nullptr;
304   views::Label* message_view_ = nullptr;
305   views::Label* status_view_ = nullptr;
306   ProportionalImageView* icon_view_ = nullptr;
307   views::View* image_container_view_ = nullptr;
308   std::vector<NotificationButtonMD*> action_buttons_;
309   std::vector<views::View*> item_views_;
310   views::ProgressBar* progress_bar_view_ = nullptr;
311   CompactTitleMessageView* compact_title_message_view_ = nullptr;
312   views::View* action_buttons_row_ = nullptr;
313   NotificationInputContainerMD* inline_reply_ = nullptr;
314 
315   // Counter for view layouting, which is used during the CreateOrUpdate*
316   // phases to keep track of the view ordering. See crbug.com/901045
317   int left_content_count_;
318 
319   // Views for inline settings.
320   views::RadioButton* block_all_button_ = nullptr;
321   views::RadioButton* dont_block_button_ = nullptr;
322   views::LabelButton* settings_done_button_ = nullptr;
323 
324   // Owned by views properties. Guaranteed to be not null for the lifetime of
325   // |this| because views properties are the last thing cleaned up.
326   NotificationViewMDPathGenerator* highlight_path_generator_ = nullptr;
327 
328   std::unique_ptr<ui::EventHandler> click_activator_;
329 
330   base::TimeTicks last_mouse_pressed_timestamp_;
331 
332   base::WeakPtrFactory<NotificationViewMD> weak_ptr_factory_{this};
333 
334   DISALLOW_COPY_AND_ASSIGN(NotificationViewMD);
335 };
336 
337 }  // namespace message_center
338 
339 #endif  // UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_MD_H_
340