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

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

Issue 2109293002: mash: Convert system tray network item to wm common types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: tweak string Created 4 years, 5 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
« no previous file with comments | « ash/system/chromeos/network/tray_sms.h ('k') | ash/system/chromeos/network/tray_vpn.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/chromeos/network/tray_sms.h"
6
7 #include "ash/common/system/tray/fixed_sized_scroll_view.h"
8 #include "ash/common/system/tray/system_tray_bubble.h"
9 #include "ash/common/system/tray/tray_constants.h"
10 #include "ash/common/system/tray/tray_details_view.h"
11 #include "ash/common/system/tray/tray_item_more.h"
12 #include "ash/common/system/tray/tray_item_view.h"
13 #include "ash/common/system/tray/tray_notification_view.h"
14 #include "ash/common/system/tray/view_click_listener.h"
15 #include "ash/shell.h"
16 #include "ash/system/tray/system_tray.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chromeos/network/network_event_log.h"
20 #include "chromeos/network/network_handler.h"
21 #include "grit/ash_resources.h"
22 #include "grit/ash_strings.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/views/bubble/tray_bubble_view.h"
26 #include "ui/views/controls/image_view.h"
27 #include "ui/views/controls/label.h"
28 #include "ui/views/layout/box_layout.h"
29 #include "ui/views/layout/fill_layout.h"
30 #include "ui/views/layout/grid_layout.h"
31 #include "ui/views/view.h"
32
33 namespace {
34
35 // Min height of the list of messages in the popup.
36 const int kMessageListMinHeight = 200;
37 // Top/bottom padding of the text items.
38 const int kPaddingVertical = 10;
39
40 const char kSmsNumberKey[] = "number";
41 const char kSmsTextKey[] = "text";
42
43 bool GetMessageFromDictionary(const base::DictionaryValue* message,
44 std::string* number,
45 std::string* text) {
46 if (!message->GetStringWithoutPathExpansion(kSmsNumberKey, number))
47 return false;
48 if (!message->GetStringWithoutPathExpansion(kSmsTextKey, text))
49 return false;
50 return true;
51 }
52
53 } // namespace
54
55 namespace ash {
56
57 class TraySms::SmsDefaultView : public TrayItemMore {
58 public:
59 explicit SmsDefaultView(TraySms* owner) : TrayItemMore(owner, true) {
60 SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
61 IDR_AURA_UBER_TRAY_SMS));
62 Update();
63 }
64
65 ~SmsDefaultView() override {}
66
67 void Update() {
68 int message_count = static_cast<TraySms*>(owner())->messages().GetSize();
69 // TODO(jshin): Currently, a tabular format is used ("SMS Messages:
70 // <count>"). Check with UX if '<count> SMS messages' with a proper plural
71 // support is desired.
72 base::string16 label = l10n_util::GetStringFUTF16Int(
73 IDS_ASH_STATUS_TRAY_SMS_MESSAGES, message_count);
74 SetLabel(label);
75 SetAccessibleName(label);
76 }
77
78 private:
79 DISALLOW_COPY_AND_ASSIGN(SmsDefaultView);
80 };
81
82 // An entry (row) in SmsDetailedView or NotificationView.
83 class TraySms::SmsMessageView : public views::View,
84 public views::ButtonListener {
85 public:
86 enum ViewType { VIEW_DETAILED, VIEW_NOTIFICATION };
87
88 SmsMessageView(TraySms* owner,
89 ViewType view_type,
90 size_t index,
91 const std::string& number,
92 const std::string& message)
93 : owner_(owner), index_(index) {
94 // TODO(jshin): Convert ASCII digits in |number| (phone number) to native
95 // digits if necessary. |number| can contain non-digit characters and may
96 // have to be converted one-by-one or use libphonenumber's formating API.
97 number_label_ = new views::Label(
98 l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_SMS_NUMBER,
99 base::UTF8ToUTF16(number)),
100 ui::ResourceBundle::GetSharedInstance().GetFontList(
101 ui::ResourceBundle::BoldFont));
102 number_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
103
104 message_label_ = new views::Label(base::UTF8ToUTF16(message));
105 message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
106 message_label_->SetMultiLine(true);
107
108 if (view_type == VIEW_DETAILED)
109 LayoutDetailedView();
110 else
111 LayoutNotificationView();
112 }
113
114 ~SmsMessageView() override {}
115
116 // Overridden from ButtonListener.
117 void ButtonPressed(views::Button* sender, const ui::Event& event) override {
118 owner_->RemoveMessage(index_);
119 owner_->Update(false);
120 }
121
122 private:
123 void LayoutDetailedView() {
124 views::ImageButton* close_button = new views::ImageButton(this);
125 close_button->SetImage(
126 views::CustomButton::STATE_NORMAL,
127 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
128 IDR_AURA_UBER_TRAY_SMS_DISMISS));
129 const int msg_width =
130 owner_->system_tray()
131 ->GetSystemBubble()
132 ->bubble_view()
133 ->GetPreferredSize()
134 .width() -
135 (kNotificationIconWidth + kTrayPopupPaddingHorizontal * 2);
136 message_label_->SizeToFit(msg_width);
137
138 views::GridLayout* layout = new views::GridLayout(this);
139 SetLayoutManager(layout);
140
141 views::ColumnSet* columns = layout->AddColumnSet(0);
142
143 // Message
144 columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal);
145 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
146 0 /* resize percent */, views::GridLayout::FIXED,
147 msg_width, msg_width);
148
149 // Close button
150 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
151 0, /* resize percent */
152 views::GridLayout::FIXED, kNotificationIconWidth,
153 kNotificationIconWidth);
154
155 layout->AddPaddingRow(0, kPaddingVertical);
156 layout->StartRow(0, 0);
157 layout->AddView(number_label_);
158 layout->AddView(close_button, 1, 2); // 2 rows for icon
159 layout->StartRow(0, 0);
160 layout->AddView(message_label_);
161
162 layout->AddPaddingRow(0, kPaddingVertical);
163 }
164
165 void LayoutNotificationView() {
166 SetLayoutManager(
167 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
168 AddChildView(number_label_);
169 message_label_->SizeToFit(kTrayNotificationContentsWidth);
170 AddChildView(message_label_);
171 }
172
173 TraySms* owner_;
174 size_t index_;
175 views::Label* number_label_;
176 views::Label* message_label_;
177
178 DISALLOW_COPY_AND_ASSIGN(SmsMessageView);
179 };
180
181 class TraySms::SmsDetailedView : public TrayDetailsView,
182 public ViewClickListener {
183 public:
184 explicit SmsDetailedView(TraySms* owner) : TrayDetailsView(owner) {
185 Init();
186 Update();
187 }
188
189 ~SmsDetailedView() override {}
190
191 void Init() {
192 CreateScrollableList();
193 CreateSpecialRow(IDS_ASH_STATUS_TRAY_SMS, this);
194 }
195
196 void Update() {
197 UpdateMessageList();
198 Layout();
199 SchedulePaint();
200 }
201
202 // Overridden from views::View.
203 gfx::Size GetPreferredSize() const override {
204 gfx::Size preferred_size = TrayDetailsView::GetPreferredSize();
205 if (preferred_size.height() < kMessageListMinHeight)
206 preferred_size.set_height(kMessageListMinHeight);
207 return preferred_size;
208 }
209
210 private:
211 void UpdateMessageList() {
212 const base::ListValue& messages =
213 static_cast<TraySms*>(owner())->messages();
214 scroll_content()->RemoveAllChildViews(true);
215 for (size_t index = 0; index < messages.GetSize(); ++index) {
216 const base::DictionaryValue* message = NULL;
217 if (!messages.GetDictionary(index, &message)) {
218 LOG(ERROR) << "SMS message not a dictionary at: " << index;
219 continue;
220 }
221 std::string number, text;
222 if (!GetMessageFromDictionary(message, &number, &text)) {
223 LOG(ERROR) << "Error parsing SMS message";
224 continue;
225 }
226 SmsMessageView* msgview = new SmsMessageView(
227 static_cast<TraySms*>(owner()), SmsMessageView::VIEW_DETAILED, index,
228 number, text);
229 scroll_content()->AddChildView(msgview);
230 }
231 scroller()->Layout();
232 }
233
234 // Overridden from ViewClickListener.
235 void OnViewClicked(views::View* sender) override {
236 if (sender == footer()->content())
237 TransitionToDefaultView();
238 }
239
240 DISALLOW_COPY_AND_ASSIGN(SmsDetailedView);
241 };
242
243 class TraySms::SmsNotificationView : public TrayNotificationView {
244 public:
245 SmsNotificationView(TraySms* owner,
246 size_t message_index,
247 const std::string& number,
248 const std::string& text)
249 : TrayNotificationView(owner, IDR_AURA_UBER_TRAY_SMS),
250 message_index_(message_index) {
251 SmsMessageView* message_view = new SmsMessageView(
252 owner, SmsMessageView::VIEW_NOTIFICATION, message_index_, number, text);
253 InitView(message_view);
254 }
255
256 void Update(size_t message_index,
257 const std::string& number,
258 const std::string& text) {
259 SmsMessageView* message_view =
260 new SmsMessageView(tray_sms(), SmsMessageView::VIEW_NOTIFICATION,
261 message_index_, number, text);
262 UpdateView(message_view);
263 }
264
265 // Overridden from TrayNotificationView:
266 void OnClose() override { tray_sms()->RemoveMessage(message_index_); }
267
268 void OnClickAction() override { owner()->PopupDetailedView(0, true); }
269
270 private:
271 TraySms* tray_sms() { return static_cast<TraySms*>(owner()); }
272
273 size_t message_index_;
274
275 DISALLOW_COPY_AND_ASSIGN(SmsNotificationView);
276 };
277
278 TraySms::TraySms(SystemTray* system_tray)
279 : SystemTrayItem(system_tray),
280 default_(NULL),
281 detailed_(NULL),
282 notification_(NULL) {
283 // TODO(armansito): SMS could be a special case for cellular that requires a
284 // user (perhaps the owner) to be logged in. If that is the case, then an
285 // additional check should be done before subscribing for SMS notifications.
286 if (chromeos::NetworkHandler::IsInitialized())
287 chromeos::NetworkHandler::Get()->network_sms_handler()->AddObserver(this);
288 }
289
290 TraySms::~TraySms() {
291 if (chromeos::NetworkHandler::IsInitialized()) {
292 chromeos::NetworkHandler::Get()->network_sms_handler()->RemoveObserver(
293 this);
294 }
295 }
296
297 views::View* TraySms::CreateDefaultView(LoginStatus status) {
298 CHECK(default_ == NULL);
299 default_ = new SmsDefaultView(this);
300 default_->SetVisible(!messages_.empty());
301 return default_;
302 }
303
304 views::View* TraySms::CreateDetailedView(LoginStatus status) {
305 CHECK(detailed_ == NULL);
306 HideNotificationView();
307 if (messages_.empty())
308 return NULL;
309 detailed_ = new SmsDetailedView(this);
310 return detailed_;
311 }
312
313 views::View* TraySms::CreateNotificationView(LoginStatus status) {
314 CHECK(notification_ == NULL);
315 if (detailed_)
316 return NULL;
317 size_t index;
318 std::string number, text;
319 if (GetLatestMessage(&index, &number, &text))
320 notification_ = new SmsNotificationView(this, index, number, text);
321 return notification_;
322 }
323
324 void TraySms::DestroyDefaultView() {
325 default_ = NULL;
326 }
327
328 void TraySms::DestroyDetailedView() {
329 detailed_ = NULL;
330 }
331
332 void TraySms::DestroyNotificationView() {
333 notification_ = NULL;
334 }
335
336 void TraySms::MessageReceived(const base::DictionaryValue& message) {
337 std::string message_text;
338 if (!message.GetStringWithoutPathExpansion(
339 chromeos::NetworkSmsHandler::kTextKey, &message_text)) {
340 NET_LOG_ERROR("SMS message contains no content.", "");
341 return;
342 }
343 // TODO(armansito): A message might be due to a special "Message Waiting"
344 // state that the message is in. Once SMS handling moves to shill, such
345 // messages should be filtered there so that this check becomes unnecessary.
346 if (message_text.empty()) {
347 NET_LOG_DEBUG("SMS has empty content text. Ignoring.", "");
348 return;
349 }
350 std::string message_number;
351 if (!message.GetStringWithoutPathExpansion(
352 chromeos::NetworkSmsHandler::kNumberKey, &message_number)) {
353 NET_LOG_DEBUG("SMS contains no number. Ignoring.", "");
354 return;
355 }
356
357 NET_LOG_DEBUG(
358 "Received SMS from: " + message_number + " with text: " + message_text,
359 "");
360
361 base::DictionaryValue* dict = new base::DictionaryValue();
362 dict->SetString(kSmsNumberKey, message_number);
363 dict->SetString(kSmsTextKey, message_text);
364 messages_.Append(dict);
365 Update(true);
366 }
367
368 bool TraySms::GetLatestMessage(size_t* index,
369 std::string* number,
370 std::string* text) {
371 if (messages_.empty())
372 return false;
373 base::DictionaryValue* message;
374 size_t message_index = messages_.GetSize() - 1;
375 if (!messages_.GetDictionary(message_index, &message))
376 return false;
377 if (!GetMessageFromDictionary(message, number, text))
378 return false;
379 *index = message_index;
380 return true;
381 }
382
383 void TraySms::RemoveMessage(size_t index) {
384 if (index < messages_.GetSize())
385 messages_.Remove(index, NULL);
386 }
387
388 void TraySms::Update(bool notify) {
389 if (messages_.empty()) {
390 if (default_)
391 default_->SetVisible(false);
392 if (detailed_)
393 HideDetailedView();
394 HideNotificationView();
395 } else {
396 if (default_) {
397 default_->SetVisible(true);
398 default_->Update();
399 }
400 if (detailed_)
401 detailed_->Update();
402 if (notification_) {
403 size_t index;
404 std::string number, text;
405 if (GetLatestMessage(&index, &number, &text))
406 notification_->Update(index, number, text);
407 } else if (notify) {
408 ShowNotificationView();
409 }
410 }
411 }
412
413 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/chromeos/network/tray_sms.h ('k') | ash/system/chromeos/network/tray_vpn.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698