Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(880)

Side by Side Diff: ash/system/network/tray_sms.cc

Issue 10332152: Add TraySms for SMS messages. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include "ash/system/network/tray_sms.h"
6
7 #include "ash/shell.h"
8 #include "ash/system/tray/system_tray.h"
9 #include "ash/system/tray/tray_constants.h"
10 #include "ash/system/tray/tray_item_more.h"
11 #include "ash/system/tray/tray_item_view.h"
12 #include "ash/system/tray/tray_views.h"
13 #include "base/string_number_conversions.h"
14 #include "base/utf_string_conversions.h"
15 #include "grit/ash_strings.h"
16 #include "grit/ui_resources.h"
17 #include "grit/ui_resources_standard.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/views/controls/image_view.h"
21 #include "ui/views/controls/label.h"
22 #include "ui/views/layout/box_layout.h"
23 #include "ui/views/layout/fill_layout.h"
24 #include "ui/views/layout/grid_layout.h"
25 #include "ui/views/view.h"
26
27 #if defined(OS_CHROMEOS)
28 #include "chromeos/network/network_sms_handler.h"
29 #endif
30
31 namespace {
32
33 // Height of the list of messages in the popup.
34 const int kMessageListHeight = 200;
35 // Top/bottom padding of the text items.
36 const int kPaddingVertical = 10;
37 const int kSmsIconWidth = 50;
38
39 } // namespace
40
41 namespace ash {
42 namespace internal {
43
44 class SmsObserverBase {
45 public:
46 explicit SmsObserverBase(TraySms* tray) : tray_(tray) {}
47 virtual ~SmsObserverBase() {}
48
49 bool GetMessageFromDictionary(const base::DictionaryValue* message,
50 std::string* number,
51 std::string* text) {
52 if (!message->GetStringWithoutPathExpansion(
53 chromeos::NetworkSmsHandler::kNumberKey, number))
54 return false;
55 if (!message->GetStringWithoutPathExpansion(
56 chromeos::NetworkSmsHandler::kTextKey, text))
57 return false;
58 return true;
59 }
60
61 void RemoveMessage(size_t index) {
62 if (index < messages_.GetSize())
63 messages_.Remove(index, NULL);
64 }
65
66 const base::ListValue& messages() const { return messages_; }
67
68 protected:
69 base::ListValue messages_;
70 TraySms* tray_;
71
72 private:
73 DISALLOW_COPY_AND_ASSIGN(SmsObserverBase);
74 };
75
76 #if defined(OS_CHROMEOS)
77
78 class TraySms::SmsObserver : public SmsObserverBase,
79 public chromeos::NetworkSmsHandler::Observer {
80 public:
81 explicit SmsObserver(TraySms* tray) : SmsObserverBase(tray) {
82 sms_handler_.reset(new chromeos::NetworkSmsHandler());
83 sms_handler_->AddObserver(this);
84 sms_handler_->Init();
85 }
86
87 virtual ~SmsObserver() {
88 sms_handler_->RemoveObserver(this);
89 }
90
91 // Overridden from chromeos::NetworkSmsHandler::Observer
92 virtual void MessageReceived(const base::DictionaryValue& message) {
93 messages_.Append(message.DeepCopy());
94 tray_->Update(true);
95 }
96
97 private:
98 scoped_ptr<chromeos::NetworkSmsHandler> sms_handler_;
99
100 DISALLOW_COPY_AND_ASSIGN(SmsObserver);
101 };
102
103 #else
104
105 class TraySms::SmsObserver : public SmsObserverBase {
106 public:
107 explicit SmsObserver(TraySms* tray) : SmsObserverBase(tray) {
108 }
109 virtual ~SmsObserver() {}
110
111 private:
112 DISALLOW_COPY_AND_ASSIGN(SmsObserver);
113 };
114
115 #endif // OS_CHROMEOS
116
117 class TraySms::SmsDefaultView : public TrayItemMore {
118 public:
119 explicit SmsDefaultView(TraySms* tray)
120 : TrayItemMore(tray),
121 tray_(tray) {
122 SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed(
123 IDR_AURA_UBER_TRAY_SMS));
124 Update();
125 }
126
127 virtual ~SmsDefaultView() {}
128
129 void Update() {
130 int message_count =
131 static_cast<int>(tray_->sms_observer()->messages().GetSize());
132 string16 label = l10n_util::GetStringFUTF16(
133 IDS_ASH_STATUS_TRAY_SMS_MESSAGES, base::IntToString16(message_count));
134 SetLabel(label);
135 SetAccessibleName(label);
136 }
137
138 private:
139 TraySms* tray_;
140
141 DISALLOW_COPY_AND_ASSIGN(SmsDefaultView);
142 };
143
144 class TraySms::SmsMessageView : public views::View,
145 public views::ButtonListener {
146 public:
147 enum ViewType {
148 VIEW_DETAILED,
149 VIEW_NOTIFICATION
150 };
151
152 SmsMessageView(TraySms* tray,
153 ViewType view_type,
154 size_t index,
155 const std::string& number,
156 const std::string& message)
157 : tray_(tray),
158 index_(index) {
159 number_label_ = new views::Label(
160 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_SMS_NUMBER,
161 UTF8ToUTF16(number)));
162 number_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
163
164 message_label_ = new views::Label(UTF8ToUTF16(message));
165 message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
166 message_label_->SetMultiLine(true);
167
168 int msg_width;
169 if (view_type == VIEW_DETAILED)
170 msg_width = LayoutDetailedView();
171 else
172 msg_width = LayoutNotificationView();
173
174 message_label_->SizeToFit(msg_width);
175 }
176
177 virtual ~SmsMessageView() {
178 }
179
180 // Overridden from ButtonListener.
181 virtual void ButtonPressed(views::Button* sender,
182 const views::Event& event) OVERRIDE {
183 tray_->sms_observer()->RemoveMessage(index_);
184 tray_->Update(false);
185 }
186
187 private:
188 int LayoutDetailedView() {
189 views::ImageButton* close_button = new views::ImageButton(this);
190 close_button->SetImage(views::CustomButton::BS_NORMAL,
191 ResourceBundle::GetSharedInstance().GetBitmapNamed(
192 IDR_AURA_WINDOW_CLOSE));
193
194 int msg_width = kTrayPopupWidth - kNotificationCloseButtonWidth -
195 kTrayPopupPaddingHorizontal * 2;
196
197 views::GridLayout* layout = new views::GridLayout(this);
198 SetLayoutManager(layout);
199
200 views::ColumnSet* columns = layout->AddColumnSet(0);
201
202 // Message
203 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal);
204 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
205 0 /* resize percent */,
206 views::GridLayout::FIXED, msg_width, msg_width);
207
208 // Close button
209 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
210 0, /* resize percent */
211 views::GridLayout::FIXED,
212 kNotificationCloseButtonWidth,
213 kNotificationCloseButtonWidth);
214
215
216 layout->AddPaddingRow(0, kPaddingVertical);
217 layout->StartRow(0, 0);
218 layout->AddView(number_label_);
219 layout->AddView(close_button, 1, 2); // 2 rows for icon
220 layout->StartRow(0, 0);
221 layout->AddView(message_label_);
222
223 layout->AddPaddingRow(0, kPaddingVertical);
224
225 return msg_width;
226 }
227
228 int LayoutNotificationView() {
229 icon_ = new views::ImageView;
230 icon_->SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed(
231 IDR_AURA_UBER_TRAY_SMS));
232
233 int msg_width = kTrayPopupWidth - kNotificationCloseButtonWidth -
234 kTrayPopupPaddingHorizontal - kSmsIconWidth;
235
236 views::GridLayout* layout = new views::GridLayout(this);
237 SetLayoutManager(layout);
238
239 views::ColumnSet* columns = layout->AddColumnSet(0);
240
241 // Icon
242 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
243 0 /* resize percent */,
244 views::GridLayout::FIXED, kSmsIconWidth, kSmsIconWidth);
245
246 // Message
247 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
248 0 /* resize percent */,
249 views::GridLayout::FIXED, msg_width, msg_width);
250
251 layout->AddPaddingRow(0, kPaddingVertical);
252
253 layout->StartRow(0, 0);
254 layout->AddView(icon_, 1, 2); // 2 rows for icon
255 layout->AddView(number_label_);
256 layout->StartRow(0, 0);
257 layout->SkipColumns(1);
258 layout->AddView(message_label_);
259 layout->StartRow(0, 0);
260
261 layout->AddPaddingRow(0, kPaddingVertical);
262
263 return msg_width;
264 }
265
266 TraySms* tray_;
267 size_t index_;
268 views::Label* number_label_;
269 views::Label* message_label_;
270 views::ImageView* icon_;
271
272 DISALLOW_COPY_AND_ASSIGN(SmsMessageView);
273 };
274
275 class TraySms::SmsDetailedView : public views::View,
276 public ViewClickListener {
277 public:
278 explicit SmsDetailedView(TraySms* tray)
279 : tray_(tray),
280 header_(NULL),
281 message_list_(NULL),
282 scroller_(NULL) {
283 SetLayoutManager(new views::BoxLayout(
284 views::BoxLayout::kVertical, 0, 0, 0));
285 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
286 Init();
287 Update();
288 }
289
290 virtual ~SmsDetailedView() {
291 }
292
293 void Init() {
294 message_list_ = new views::View;
295 message_list_->SetLayoutManager(new views::BoxLayout(
296 views::BoxLayout::kVertical, 0, 0, 1));
297
298 scroller_ = new FixedSizedScrollView;
299 scroller_->set_border(views::Border::CreateSolidSidedBorder(
300 1, 0, 1, 0, SkColorSetARGB(25, 0, 0, 0)));
301 scroller_->set_fixed_size(
302 gfx::Size(message_list_->GetPreferredSize().width() +
303 scroller_->GetScrollBarWidth(),
304 kMessageListHeight));
305 scroller_->SetContentsView(message_list_);
306 AddChildView(scroller_);
307
308 header_ = new SpecialPopupRow();
309 header_->SetTextLabel(IDS_ASH_STATUS_TRAY_SMS, this);
310 AddChildView(header_);
311 }
312
313 void Update() {
314 UpdateMessageList();
315 scroller_->Layout();
316 SchedulePaint();
317 }
318
319 private:
320 void UpdateMessageList() {
321 const base::ListValue& messages = tray_->sms_observer()->messages();
322 message_list_->RemoveAllChildViews(true);
323
324 for (size_t index = 0; index < messages.GetSize(); ++index) {
325 base::DictionaryValue* message = NULL;
326 if (!messages.GetDictionary(index, &message)) {
327 LOG(ERROR) << "SMS message not a dictionary at: " << index;
328 continue;
329 }
330 std::string number, text;
331 if (!tray_->sms_observer()->GetMessageFromDictionary(
332 message, &number, &text)) {
333 LOG(ERROR) << "Error parsing SMS message";
334 continue;
335 }
336 SmsMessageView* msgview = new SmsMessageView(
337 tray_, SmsMessageView::VIEW_DETAILED, index, number, text);
338 message_list_->AddChildView(msgview);
339 }
340 message_list_->SizeToPreferredSize();
341 }
342
343 // Overridden from ViewClickListener.
344 virtual void ClickedOn(views::View* sender) OVERRIDE {
345 if (sender == header_->content())
346 Shell::GetInstance()->tray()->ShowDefaultView();
347 }
348
349 TraySms* tray_;
350 SpecialPopupRow* header_;
351 views::View* message_list_;
352 FixedSizedScrollView* scroller_;
353
354 DISALLOW_COPY_AND_ASSIGN(SmsDetailedView);
355 };
356
357 class TraySms::SmsNotificationView : public TrayNotificationView {
358 public:
359 SmsNotificationView(TraySms* tray,
360 const std::string& number,
361 const std::string& text,
362 size_t message_index)
363 : tray_(tray),
364 message_index_(message_index) {
365 SmsMessageView* message_view_ = new SmsMessageView(
366 tray_, SmsMessageView::VIEW_NOTIFICATION, message_index, number, text);
367 InitView(message_view_);
368 }
369
370 // Overridden from views::View.
371 bool OnMousePressed(const views::MouseEvent& event) {
372 tray_->PopupDetailedView(0, true);
373 return true;
374 }
375
376 // Overridden from TrayNotificationView:
377 virtual void OnClose() OVERRIDE {
378 tray_->sms_observer()->RemoveMessage(message_index_);
379 tray_->HideNotificationView();
380 }
381
382 private:
383 TraySms* tray_;
384 SmsMessageView* message_view_;
385 size_t message_index_;
386
387 DISALLOW_COPY_AND_ASSIGN(SmsNotificationView);
388 };
389
390 TraySms::TraySms()
391 : TrayImageItem(IDR_AURA_UBER_TRAY_SMS),
392 default_(NULL),
393 detailed_(NULL),
394 notification_(NULL) {
395 sms_observer_.reset(new SmsObserver(this));
396 }
397
398 TraySms::~TraySms() {
399 }
400
401 bool TraySms::GetInitialVisibility() {
402 return !sms_observer()->messages().empty();
403 }
404
405 views::View* TraySms::CreateDefaultView(user::LoginStatus status) {
406 CHECK(default_ == NULL);
407 default_ = new SmsDefaultView(this);
408 default_->SetVisible(!sms_observer()->messages().empty());
409 return default_;
410 }
411
412 views::View* TraySms::CreateDetailedView(user::LoginStatus status) {
413 CHECK(detailed_ == NULL);
414 HideNotificationView();
415 if (sms_observer()->messages().empty())
416 return NULL;
417 detailed_ = new SmsDetailedView(this);
418 return detailed_;
419 }
420
421 views::View* TraySms::CreateNotificationView(user::LoginStatus status) {
422 CHECK(notification_ == NULL);
423 const base::ListValue& messages = sms_observer()->messages();
424 if (messages.empty())
425 return NULL;
426 DictionaryValue* message;
427 size_t message_index = messages.GetSize() - 1;
428 if (!messages.GetDictionary(message_index, &message))
429 return NULL;
430 std::string number, text;
431 if (!sms_observer()->GetMessageFromDictionary(message, &number, &text))
432 return NULL;
433 notification_ = new SmsNotificationView(this, number, text, message_index);
434 return notification_;
435 }
436
437 void TraySms::DestroyDefaultView() {
438 default_ = NULL;
439 }
440
441 void TraySms::DestroyDetailedView() {
442 detailed_ = NULL;
443 }
444
445 void TraySms::DestroyNotificationView() {
446 notification_ = NULL;
447 }
448
449 void TraySms::Update(bool notify) {
450 HideNotificationView();
451 if (sms_observer()->messages().empty()) {
452 if (tray_view())
453 tray_view()->SetVisible(false);
454 if (default_)
455 default_->SetVisible(false);
456 if (detailed_)
457 HideDetailedView();
458 } else {
459 if (tray_view())
460 tray_view()->SetVisible(true);
461 if (default_) {
462 default_->SetVisible(true);
463 default_->Update();
464 }
465 if (detailed_)
466 detailed_->Update();
467 else if (notify)
468 ShowNotificationView();
469 }
470 }
471
472 } // namespace internal
473 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698