Index: ash/system/network/tray_sms.cc |
diff --git a/ash/system/network/tray_sms.cc b/ash/system/network/tray_sms.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..12ac9eee68741425fe67431c999ad854caa263ba |
--- /dev/null |
+++ b/ash/system/network/tray_sms.cc |
@@ -0,0 +1,473 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ash/system/network/tray_sms.h" |
+ |
+#include "ash/shell.h" |
+#include "ash/system/tray/system_tray.h" |
+#include "ash/system/tray/tray_constants.h" |
+#include "ash/system/tray/tray_item_more.h" |
+#include "ash/system/tray/tray_item_view.h" |
+#include "ash/system/tray/tray_views.h" |
+#include "base/string_number_conversions.h" |
+#include "base/utf_string_conversions.h" |
+#include "grit/ash_strings.h" |
+#include "grit/ui_resources.h" |
+#include "grit/ui_resources_standard.h" |
+#include "ui/base/l10n/l10n_util.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/views/controls/image_view.h" |
+#include "ui/views/controls/label.h" |
+#include "ui/views/layout/box_layout.h" |
+#include "ui/views/layout/fill_layout.h" |
+#include "ui/views/layout/grid_layout.h" |
+#include "ui/views/view.h" |
+ |
+#if defined(OS_CHROMEOS) |
+#include "chromeos/network/network_sms_handler.h" |
+#endif |
+ |
+namespace { |
+ |
+// Height of the list of messages in the popup. |
+const int kMessageListHeight = 200; |
+// Top/bottom padding of the text items. |
+const int kPaddingVertical = 10; |
+const int kSmsIconWidth = 50; |
+ |
+} // namespace |
+ |
+namespace ash { |
+namespace internal { |
+ |
+class SmsObserverBase { |
+ public: |
+ explicit SmsObserverBase(TraySms* tray) : tray_(tray) {} |
+ virtual ~SmsObserverBase() {} |
+ |
+ bool GetMessageFromDictionary(const base::DictionaryValue* message, |
+ std::string* number, |
+ std::string* text) { |
+ if (!message->GetStringWithoutPathExpansion( |
+ chromeos::NetworkSmsHandler::kNumberKey, number)) |
+ return false; |
+ if (!message->GetStringWithoutPathExpansion( |
+ chromeos::NetworkSmsHandler::kTextKey, text)) |
+ return false; |
+ return true; |
+ } |
+ |
+ void RemoveMessage(size_t index) { |
+ if (index < messages_.GetSize()) |
+ messages_.Remove(index, NULL); |
+ } |
+ |
+ const base::ListValue& messages() const { return messages_; } |
+ |
+ protected: |
+ base::ListValue messages_; |
+ TraySms* tray_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SmsObserverBase); |
+}; |
+ |
+#if defined(OS_CHROMEOS) |
+ |
+class TraySms::SmsObserver : public SmsObserverBase, |
+ public chromeos::NetworkSmsHandler::Observer { |
+ public: |
+ explicit SmsObserver(TraySms* tray) : SmsObserverBase(tray) { |
+ sms_handler_.reset(new chromeos::NetworkSmsHandler()); |
+ sms_handler_->AddObserver(this); |
+ sms_handler_->Init(); |
+ } |
+ |
+ virtual ~SmsObserver() { |
+ sms_handler_->RemoveObserver(this); |
+ } |
+ |
+ // Overridden from chromeos::NetworkSmsHandler::Observer |
+ virtual void MessageReceived(const base::DictionaryValue& message) { |
+ messages_.Append(message.DeepCopy()); |
+ tray_->Update(true); |
+ } |
+ |
+ private: |
+ scoped_ptr<chromeos::NetworkSmsHandler> sms_handler_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SmsObserver); |
+}; |
+ |
+#else |
+ |
+class TraySms::SmsObserver : public SmsObserverBase { |
+ public: |
+ explicit SmsObserver(TraySms* tray) : SmsObserverBase(tray) { |
+ } |
+ virtual ~SmsObserver() {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SmsObserver); |
+}; |
+ |
+#endif // OS_CHROMEOS |
+ |
+class TraySms::SmsDefaultView : public TrayItemMore { |
+ public: |
+ explicit SmsDefaultView(TraySms* tray) |
+ : TrayItemMore(tray), |
+ tray_(tray) { |
+ SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed( |
+ IDR_AURA_UBER_TRAY_SMS)); |
+ Update(); |
+ } |
+ |
+ virtual ~SmsDefaultView() {} |
+ |
+ void Update() { |
+ int message_count = |
+ static_cast<int>(tray_->sms_observer()->messages().GetSize()); |
+ string16 label = l10n_util::GetStringFUTF16( |
+ IDS_ASH_STATUS_TRAY_SMS_MESSAGES, base::IntToString16(message_count)); |
+ SetLabel(label); |
+ SetAccessibleName(label); |
+ } |
+ |
+ private: |
+ TraySms* tray_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SmsDefaultView); |
+}; |
+ |
+class TraySms::SmsMessageView : public views::View, |
+ public views::ButtonListener { |
+ public: |
+ enum ViewType { |
+ VIEW_DETAILED, |
+ VIEW_NOTIFICATION |
+ }; |
+ |
+ SmsMessageView(TraySms* tray, |
+ ViewType view_type, |
+ size_t index, |
+ const std::string& number, |
+ const std::string& message) |
+ : tray_(tray), |
+ index_(index) { |
+ number_label_ = new views::Label( |
+ l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_SMS_NUMBER, |
+ UTF8ToUTF16(number))); |
+ number_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ |
+ message_label_ = new views::Label(UTF8ToUTF16(message)); |
+ message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ message_label_->SetMultiLine(true); |
+ |
+ int msg_width; |
+ if (view_type == VIEW_DETAILED) |
+ msg_width = LayoutDetailedView(); |
+ else |
+ msg_width = LayoutNotificationView(); |
+ |
+ message_label_->SizeToFit(msg_width); |
+ } |
+ |
+ virtual ~SmsMessageView() { |
+ } |
+ |
+ // Overridden from ButtonListener. |
+ virtual void ButtonPressed(views::Button* sender, |
+ const views::Event& event) OVERRIDE { |
+ tray_->sms_observer()->RemoveMessage(index_); |
+ tray_->Update(false); |
+ } |
+ |
+ private: |
+ int LayoutDetailedView() { |
+ views::ImageButton* close_button = new views::ImageButton(this); |
+ close_button->SetImage(views::CustomButton::BS_NORMAL, |
+ ResourceBundle::GetSharedInstance().GetBitmapNamed( |
+ IDR_AURA_WINDOW_CLOSE)); |
+ |
+ int msg_width = kTrayPopupWidth - kNotificationCloseButtonWidth - |
+ kTrayPopupPaddingHorizontal * 2; |
+ |
+ views::GridLayout* layout = new views::GridLayout(this); |
+ SetLayoutManager(layout); |
+ |
+ views::ColumnSet* columns = layout->AddColumnSet(0); |
+ |
+ // Message |
+ columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal); |
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
+ 0 /* resize percent */, |
+ views::GridLayout::FIXED, msg_width, msg_width); |
+ |
+ // Close button |
+ columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, |
+ 0, /* resize percent */ |
+ views::GridLayout::FIXED, |
+ kNotificationCloseButtonWidth, |
+ kNotificationCloseButtonWidth); |
+ |
+ |
+ layout->AddPaddingRow(0, kPaddingVertical); |
+ layout->StartRow(0, 0); |
+ layout->AddView(number_label_); |
+ layout->AddView(close_button, 1, 2); // 2 rows for icon |
+ layout->StartRow(0, 0); |
+ layout->AddView(message_label_); |
+ |
+ layout->AddPaddingRow(0, kPaddingVertical); |
+ |
+ return msg_width; |
+ } |
+ |
+ int LayoutNotificationView() { |
+ icon_ = new views::ImageView; |
+ icon_->SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed( |
+ IDR_AURA_UBER_TRAY_SMS)); |
+ |
+ int msg_width = kTrayPopupWidth - kNotificationCloseButtonWidth - |
+ kTrayPopupPaddingHorizontal - kSmsIconWidth; |
+ |
+ views::GridLayout* layout = new views::GridLayout(this); |
+ SetLayoutManager(layout); |
+ |
+ views::ColumnSet* columns = layout->AddColumnSet(0); |
+ |
+ // Icon |
+ columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, |
+ 0 /* resize percent */, |
+ views::GridLayout::FIXED, kSmsIconWidth, kSmsIconWidth); |
+ |
+ // Message |
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
+ 0 /* resize percent */, |
+ views::GridLayout::FIXED, msg_width, msg_width); |
+ |
+ layout->AddPaddingRow(0, kPaddingVertical); |
+ |
+ layout->StartRow(0, 0); |
+ layout->AddView(icon_, 1, 2); // 2 rows for icon |
+ layout->AddView(number_label_); |
+ layout->StartRow(0, 0); |
+ layout->SkipColumns(1); |
+ layout->AddView(message_label_); |
+ layout->StartRow(0, 0); |
+ |
+ layout->AddPaddingRow(0, kPaddingVertical); |
+ |
+ return msg_width; |
+ } |
+ |
+ TraySms* tray_; |
+ size_t index_; |
+ views::Label* number_label_; |
+ views::Label* message_label_; |
+ views::ImageView* icon_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SmsMessageView); |
+}; |
+ |
+class TraySms::SmsDetailedView : public views::View, |
+ public ViewClickListener { |
+ public: |
+ explicit SmsDetailedView(TraySms* tray) |
+ : tray_(tray), |
+ header_(NULL), |
+ message_list_(NULL), |
+ scroller_(NULL) { |
+ SetLayoutManager(new views::BoxLayout( |
+ views::BoxLayout::kVertical, 0, 0, 0)); |
+ set_background(views::Background::CreateSolidBackground(kBackgroundColor)); |
+ Init(); |
+ Update(); |
+ } |
+ |
+ virtual ~SmsDetailedView() { |
+ } |
+ |
+ void Init() { |
+ message_list_ = new views::View; |
+ message_list_->SetLayoutManager(new views::BoxLayout( |
+ views::BoxLayout::kVertical, 0, 0, 1)); |
+ |
+ scroller_ = new FixedSizedScrollView; |
+ scroller_->set_border(views::Border::CreateSolidSidedBorder( |
+ 1, 0, 1, 0, SkColorSetARGB(25, 0, 0, 0))); |
+ scroller_->set_fixed_size( |
+ gfx::Size(message_list_->GetPreferredSize().width() + |
+ scroller_->GetScrollBarWidth(), |
+ kMessageListHeight)); |
+ scroller_->SetContentsView(message_list_); |
+ AddChildView(scroller_); |
+ |
+ header_ = new SpecialPopupRow(); |
+ header_->SetTextLabel(IDS_ASH_STATUS_TRAY_SMS, this); |
+ AddChildView(header_); |
+ } |
+ |
+ void Update() { |
+ UpdateMessageList(); |
+ scroller_->Layout(); |
+ SchedulePaint(); |
+ } |
+ |
+ private: |
+ void UpdateMessageList() { |
+ const base::ListValue& messages = tray_->sms_observer()->messages(); |
+ message_list_->RemoveAllChildViews(true); |
+ |
+ for (size_t index = 0; index < messages.GetSize(); ++index) { |
+ base::DictionaryValue* message = NULL; |
+ if (!messages.GetDictionary(index, &message)) { |
+ LOG(ERROR) << "SMS message not a dictionary at: " << index; |
+ continue; |
+ } |
+ std::string number, text; |
+ if (!tray_->sms_observer()->GetMessageFromDictionary( |
+ message, &number, &text)) { |
+ LOG(ERROR) << "Error parsing SMS message"; |
+ continue; |
+ } |
+ SmsMessageView* msgview = new SmsMessageView( |
+ tray_, SmsMessageView::VIEW_DETAILED, index, number, text); |
+ message_list_->AddChildView(msgview); |
+ } |
+ message_list_->SizeToPreferredSize(); |
+ } |
+ |
+ // Overridden from ViewClickListener. |
+ virtual void ClickedOn(views::View* sender) OVERRIDE { |
+ if (sender == header_->content()) |
+ Shell::GetInstance()->tray()->ShowDefaultView(); |
+ } |
+ |
+ TraySms* tray_; |
+ SpecialPopupRow* header_; |
+ views::View* message_list_; |
+ FixedSizedScrollView* scroller_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SmsDetailedView); |
+}; |
+ |
+class TraySms::SmsNotificationView : public TrayNotificationView { |
+ public: |
+ SmsNotificationView(TraySms* tray, |
+ const std::string& number, |
+ const std::string& text, |
+ size_t message_index) |
+ : tray_(tray), |
+ message_index_(message_index) { |
+ SmsMessageView* message_view_ = new SmsMessageView( |
+ tray_, SmsMessageView::VIEW_NOTIFICATION, message_index, number, text); |
+ InitView(message_view_); |
+ } |
+ |
+ // Overridden from views::View. |
+ bool OnMousePressed(const views::MouseEvent& event) { |
+ tray_->PopupDetailedView(0, true); |
+ return true; |
+ } |
+ |
+ // Overridden from TrayNotificationView: |
+ virtual void OnClose() OVERRIDE { |
+ tray_->sms_observer()->RemoveMessage(message_index_); |
+ tray_->HideNotificationView(); |
+ } |
+ |
+ private: |
+ TraySms* tray_; |
+ SmsMessageView* message_view_; |
+ size_t message_index_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SmsNotificationView); |
+}; |
+ |
+TraySms::TraySms() |
+ : TrayImageItem(IDR_AURA_UBER_TRAY_SMS), |
+ default_(NULL), |
+ detailed_(NULL), |
+ notification_(NULL) { |
+ sms_observer_.reset(new SmsObserver(this)); |
+} |
+ |
+TraySms::~TraySms() { |
+} |
+ |
+bool TraySms::GetInitialVisibility() { |
+ return !sms_observer()->messages().empty(); |
+} |
+ |
+views::View* TraySms::CreateDefaultView(user::LoginStatus status) { |
+ CHECK(default_ == NULL); |
+ default_ = new SmsDefaultView(this); |
+ default_->SetVisible(!sms_observer()->messages().empty()); |
+ return default_; |
+} |
+ |
+views::View* TraySms::CreateDetailedView(user::LoginStatus status) { |
+ CHECK(detailed_ == NULL); |
+ HideNotificationView(); |
+ if (sms_observer()->messages().empty()) |
+ return NULL; |
+ detailed_ = new SmsDetailedView(this); |
+ return detailed_; |
+} |
+ |
+views::View* TraySms::CreateNotificationView(user::LoginStatus status) { |
+ CHECK(notification_ == NULL); |
+ const base::ListValue& messages = sms_observer()->messages(); |
+ if (messages.empty()) |
+ return NULL; |
+ DictionaryValue* message; |
+ size_t message_index = messages.GetSize() - 1; |
+ if (!messages.GetDictionary(message_index, &message)) |
+ return NULL; |
+ std::string number, text; |
+ if (!sms_observer()->GetMessageFromDictionary(message, &number, &text)) |
+ return NULL; |
+ notification_ = new SmsNotificationView(this, number, text, message_index); |
+ return notification_; |
+} |
+ |
+void TraySms::DestroyDefaultView() { |
+ default_ = NULL; |
+} |
+ |
+void TraySms::DestroyDetailedView() { |
+ detailed_ = NULL; |
+} |
+ |
+void TraySms::DestroyNotificationView() { |
+ notification_ = NULL; |
+} |
+ |
+void TraySms::Update(bool notify) { |
+ HideNotificationView(); |
+ if (sms_observer()->messages().empty()) { |
+ if (tray_view()) |
+ tray_view()->SetVisible(false); |
+ if (default_) |
+ default_->SetVisible(false); |
+ if (detailed_) |
+ HideDetailedView(); |
+ } else { |
+ if (tray_view()) |
+ tray_view()->SetVisible(true); |
+ if (default_) { |
+ default_->SetVisible(true); |
+ default_->Update(); |
+ } |
+ if (detailed_) |
+ detailed_->Update(); |
+ else if (notify) |
+ ShowNotificationView(); |
+ } |
+} |
+ |
+} // namespace internal |
+} // namespace ash |