tray_network.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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_network.h" 6 7#include "ash/shell.h" 8#include "ash/system/chromeos/network/network_list_detailed_view_base.h" 9#include "ash/system/tray/system_tray.h" 10#include "ash/system/tray/system_tray_delegate.h" 11#include "ash/system/tray/tray_constants.h" 12#include "ash/system/tray/tray_item_more.h" 13#include "ash/system/tray/tray_item_view.h" 14#include "ash/system/tray/tray_notification_view.h" 15#include "grit/ash_resources.h" 16#include "grit/ash_strings.h" 17#include "ui/base/l10n/l10n_util.h" 18#include "ui/base/resource/resource_bundle.h" 19#include "ui/views/controls/link.h" 20#include "ui/views/controls/link_listener.h" 21#include "ui/views/layout/box_layout.h" 22 23namespace { 24 25using ash::internal::TrayNetwork; 26 27int GetMessageIcon(TrayNetwork::MessageType message_type) { 28 switch(message_type) { 29 case TrayNetwork::ERROR_CONNECT_FAILED: 30 return IDR_AURA_UBER_TRAY_NETWORK_FAILED; 31 case TrayNetwork::MESSAGE_DATA_LOW: 32 return IDR_AURA_UBER_TRAY_NETWORK_DATA_LOW; 33 case TrayNetwork::MESSAGE_DATA_NONE: 34 return IDR_AURA_UBER_TRAY_NETWORK_DATA_NONE; 35 case TrayNetwork::MESSAGE_DATA_PROMO: 36 return IDR_AURA_UBER_TRAY_NOTIFICATION_3G; 37 } 38 NOTREACHED(); 39 return 0; 40} 41 42} // namespace 43 44namespace ash { 45namespace internal { 46 47namespace tray { 48 49enum ColorTheme { 50 LIGHT, 51 DARK, 52}; 53 54class NetworkMessages { 55 public: 56 struct Message { 57 Message() : delegate(NULL) {} 58 Message(NetworkTrayDelegate* in_delegate, 59 const string16& in_title, 60 const string16& in_message, 61 const std::vector<string16>& in_links) : 62 delegate(in_delegate), 63 title(in_title), 64 message(in_message), 65 links(in_links) {} 66 NetworkTrayDelegate* delegate; 67 string16 title; 68 string16 message; 69 std::vector<string16> links; 70 }; 71 typedef std::map<TrayNetwork::MessageType, Message> MessageMap; 72 73 MessageMap& messages() { return messages_; } 74 const MessageMap& messages() const { return messages_; } 75 76 private: 77 MessageMap messages_; 78}; 79 80class NetworkTrayView : public TrayItemView { 81 public: 82 NetworkTrayView(ColorTheme size, bool tray_icon) 83 : color_theme_(size), tray_icon_(tray_icon) { 84 SetLayoutManager( 85 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); 86 87 image_view_ = color_theme_ == DARK ? 88 new FixedSizedImageView(0, kTrayPopupItemHeight) : 89 new views::ImageView; 90 AddChildView(image_view_); 91 92 NetworkIconInfo info; 93 Shell::GetInstance()->tray_delegate()-> 94 GetMostRelevantNetworkIcon(&info, false); 95 Update(info); 96 } 97 98 virtual ~NetworkTrayView() {} 99 100 void Update(const NetworkIconInfo& info) { 101 image_view_->SetImage(info.image); 102 if (tray_icon_) 103 SetVisible(info.tray_icon_visible); 104 SchedulePaint(); 105 } 106 107 private: 108 views::ImageView* image_view_; 109 ColorTheme color_theme_; 110 bool tray_icon_; 111 112 DISALLOW_COPY_AND_ASSIGN(NetworkTrayView); 113}; 114 115class NetworkDefaultView : public TrayItemMore { 116 public: 117 NetworkDefaultView(SystemTrayItem* owner, bool show_more) 118 : TrayItemMore(owner, show_more) { 119 Update(); 120 } 121 122 virtual ~NetworkDefaultView() {} 123 124 void Update() { 125 NetworkIconInfo info; 126 Shell::GetInstance()->tray_delegate()-> 127 GetMostRelevantNetworkIcon(&info, true); 128 SetImage(&info.image); 129 SetLabel(info.description); 130 SetAccessibleName(info.description); 131 } 132 133 private: 134 DISALLOW_COPY_AND_ASSIGN(NetworkDefaultView); 135}; 136 137class NetworkListDetailedView : public NetworkListDetailedViewBase { 138 public: 139 NetworkListDetailedView(user::LoginStatus login, int header_string_id) 140 : NetworkListDetailedViewBase(login, header_string_id), 141 airplane_(NULL), 142 button_wifi_(NULL), 143 button_mobile_(NULL), 144 view_mobile_account_(NULL), 145 setup_mobile_account_(NULL), 146 other_wifi_(NULL), 147 turn_on_wifi_(NULL), 148 other_mobile_(NULL) { 149 } 150 151 virtual ~NetworkListDetailedView() { 152 } 153 154 // Overridden from NetworkListDetailedViewBase: 155 156 virtual void AppendHeaderButtons() OVERRIDE { 157 button_wifi_ = new TrayPopupHeaderButton(this, 158 IDR_AURA_UBER_TRAY_WIFI_ENABLED, 159 IDR_AURA_UBER_TRAY_WIFI_DISABLED, 160 IDR_AURA_UBER_TRAY_WIFI_ENABLED_HOVER, 161 IDR_AURA_UBER_TRAY_WIFI_DISABLED_HOVER, 162 IDS_ASH_STATUS_TRAY_WIFI); 163 button_wifi_->SetTooltipText( 164 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_WIFI)); 165 button_wifi_->SetToggledTooltipText( 166 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_WIFI)); 167 footer()->AddButton(button_wifi_); 168 169 button_mobile_ = new TrayPopupHeaderButton(this, 170 IDR_AURA_UBER_TRAY_CELLULAR_ENABLED, 171 IDR_AURA_UBER_TRAY_CELLULAR_DISABLED, 172 IDR_AURA_UBER_TRAY_CELLULAR_ENABLED_HOVER, 173 IDR_AURA_UBER_TRAY_CELLULAR_DISABLED_HOVER, 174 IDS_ASH_STATUS_TRAY_CELLULAR); 175 button_mobile_->SetTooltipText( 176 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_MOBILE)); 177 button_mobile_->SetToggledTooltipText( 178 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_MOBILE)); 179 footer()->AddButton(button_mobile_); 180 181 AppendInfoButtonToHeader(); 182 } 183 184 virtual void UpdateHeaderButtons() OVERRIDE { 185 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); 186 button_wifi_->SetToggled(!delegate->GetWifiEnabled()); 187 button_mobile_->SetToggled(!delegate->GetMobileEnabled()); 188 button_mobile_->SetVisible(delegate->GetMobileAvailable()); 189 UpdateSettingButton(); 190 } 191 192 virtual void AppendNetworkEntries() OVERRIDE { 193 CreateScrollableList(); 194 195 HoverHighlightView* container = new HoverHighlightView(this); 196 container->set_fixed_height(kTrayPopupItemHeight); 197 container->AddLabel(ui::ResourceBundle::GetSharedInstance(). 198 GetLocalizedString(IDS_ASH_STATUS_TRAY_MOBILE_VIEW_ACCOUNT), 199 gfx::Font::NORMAL); 200 AddChildView(container); 201 view_mobile_account_ = container; 202 203 container = new HoverHighlightView(this); 204 container->set_fixed_height(kTrayPopupItemHeight); 205 container->AddLabel(ui::ResourceBundle::GetSharedInstance(). 206 GetLocalizedString(IDS_ASH_STATUS_TRAY_SETUP_MOBILE), 207 gfx::Font::NORMAL); 208 AddChildView(container); 209 setup_mobile_account_ = container; 210 } 211 212 virtual void GetAvailableNetworkList( 213 std::vector<NetworkIconInfo>* list) OVERRIDE { 214 Shell::GetInstance()->tray_delegate()->GetAvailableNetworks(list); 215 } 216 217 virtual void RefreshNetworkScrollWithEmptyNetworkList() OVERRIDE { 218 ClearNetworkScrollWithEmptyNetworkList(); 219 HoverHighlightView* container = new HoverHighlightView(this); 220 container->set_fixed_height(kTrayPopupItemHeight); 221 222 if (Shell::GetInstance()->tray_delegate()->GetWifiEnabled()) { 223 NetworkIconInfo info; 224 Shell::GetInstance()->tray_delegate()-> 225 GetMostRelevantNetworkIcon(&info, true); 226 container->AddIconAndLabel(info.image, 227 info.description, 228 gfx::Font::NORMAL); 229 container->set_border(views::Border::CreateEmptyBorder(0, 230 kTrayPopupPaddingHorizontal, 0, 0)); 231 232 } else { 233 container->AddLabel(ui::ResourceBundle::GetSharedInstance(). 234 GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED), 235 gfx::Font::NORMAL); 236 } 237 238 scroll_content()->AddChildViewAt(container, 0); 239 scroll_content()->SizeToPreferredSize(); 240 static_cast<views::View*>(scroller())->Layout(); 241 } 242 243 virtual void UpdateNetworkEntries() OVERRIDE { 244 RefreshNetworkScrollWithUpdatedNetworkData(); 245 246 view_mobile_account_->SetVisible(false); 247 setup_mobile_account_->SetVisible(false); 248 249 if (login() == user::LOGGED_IN_NONE) 250 return; 251 252 std::string carrier_id, topup_url, setup_url; 253 if (Shell::GetInstance()->tray_delegate()-> 254 GetCellularCarrierInfo(&carrier_id, 255 &topup_url, 256 &setup_url)) { 257 if (carrier_id != carrier_id_) { 258 carrier_id_ = carrier_id; 259 if (!topup_url.empty()) 260 topup_url_ = topup_url; 261 } 262 263 if (!setup_url.empty()) 264 setup_url_ = setup_url; 265 266 if (!topup_url_.empty()) 267 view_mobile_account_->SetVisible(true); 268 if (!setup_url_.empty()) 269 setup_mobile_account_->SetVisible(true); 270 } 271 } 272 273 virtual void AppendCustomButtonsToBottomRow( 274 TrayPopupTextButtonContainer* bottom_row) OVERRIDE { 275 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 276 other_wifi_ = new TrayPopupTextButton(this, 277 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_WIFI)); 278 bottom_row->AddTextButton(other_wifi_); 279 280 turn_on_wifi_ = new TrayPopupTextButton(this, 281 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_TURN_ON_WIFI)); 282 bottom_row->AddTextButton(turn_on_wifi_); 283 284 other_mobile_ = new TrayPopupTextButton(this, 285 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_OTHER_MOBILE)); 286 bottom_row->AddTextButton(other_mobile_); 287 } 288 289 virtual void UpdateNetworkExtra() OVERRIDE { 290 if (login() == user::LOGGED_IN_LOCKED) 291 return; 292 293 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); 294 if (IsNetworkListEmpty() && !delegate->GetWifiEnabled()) { 295 turn_on_wifi_->SetVisible(true); 296 other_wifi_->SetVisible(false); 297 } else { 298 turn_on_wifi_->SetVisible(false); 299 other_wifi_->SetVisible(true); 300 other_wifi_->SetEnabled(delegate->GetWifiEnabled()); 301 } 302 other_mobile_->SetVisible(delegate->GetMobileAvailable() && 303 delegate->GetMobileScanSupported()); 304 if (other_mobile_->visible()) 305 other_mobile_->SetEnabled(delegate->GetMobileEnabled()); 306 307 turn_on_wifi_->parent()->Layout(); 308 } 309 310 virtual void CustomButtonPressed(views::Button* sender, 311 const ui::Event& event) OVERRIDE { 312 ash::SystemTrayDelegate* delegate = 313 ash::Shell::GetInstance()->tray_delegate(); 314 if (sender == button_wifi_) 315 delegate->ToggleWifi(); 316 else if (sender == button_mobile_) 317 delegate->ToggleMobile(); 318 else if (sender == other_mobile_) 319 delegate->ShowOtherCellular(); 320 else if (sender == other_wifi_) 321 delegate->ShowOtherWifi(); 322 else if (sender == turn_on_wifi_) 323 delegate->ToggleWifi(); 324 else 325 NOTREACHED(); 326 } 327 328 virtual bool CustomLinkClickedOn(views::View* sender) OVERRIDE { 329 ash::SystemTrayDelegate* delegate = 330 ash::Shell::GetInstance()->tray_delegate(); 331 if (sender == view_mobile_account_) { 332 delegate->ShowCellularURL(topup_url_); 333 return true; 334 } else if (sender == setup_mobile_account_) { 335 delegate->ShowCellularURL(setup_url_); 336 return true; 337 } else if (sender == airplane_) { 338 delegate->ToggleAirplaneMode(); 339 return true; 340 } else { 341 return false; 342 } 343 } 344 345 private: 346 std::string carrier_id_; 347 std::string topup_url_; 348 std::string setup_url_; 349 350 views::View* airplane_; 351 TrayPopupHeaderButton* button_wifi_; 352 TrayPopupHeaderButton* button_mobile_; 353 views::View* view_mobile_account_; 354 views::View* setup_mobile_account_; 355 TrayPopupTextButton* other_wifi_; 356 TrayPopupTextButton* turn_on_wifi_; 357 TrayPopupTextButton* other_mobile_; 358 359 DISALLOW_COPY_AND_ASSIGN(NetworkListDetailedView); 360}; 361 362class NetworkWifiDetailedView : public NetworkDetailedView { 363 public: 364 explicit NetworkWifiDetailedView(bool wifi_enabled) { 365 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 366 kTrayPopupPaddingHorizontal, 367 10, 368 kTrayPopupPaddingBetweenItems)); 369 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 370 views::ImageView* image = new views::ImageView; 371 const int image_id = wifi_enabled ? 372 IDR_AURA_UBER_TRAY_WIFI_ENABLED : IDR_AURA_UBER_TRAY_WIFI_DISABLED; 373 image->SetImage(bundle.GetImageNamed(image_id).ToImageSkia()); 374 AddChildView(image); 375 376 const int string_id = wifi_enabled ? 377 IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED: 378 IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; 379 views::Label* label = 380 new views::Label(bundle.GetLocalizedString(string_id)); 381 label->SetMultiLine(true); 382 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 383 AddChildView(label); 384 } 385 386 virtual ~NetworkWifiDetailedView() {} 387 388 // Overridden from NetworkDetailedView: 389 390 virtual void Init() OVERRIDE { 391 } 392 393 virtual NetworkDetailedView::DetailedViewType GetViewType() const OVERRIDE { 394 return NetworkDetailedView::WIFI_VIEW; 395 } 396 397 virtual void Update() OVERRIDE {} 398 399 private: 400 DISALLOW_COPY_AND_ASSIGN(NetworkWifiDetailedView); 401}; 402 403class NetworkMessageView : public views::View, 404 public views::LinkListener { 405 public: 406 NetworkMessageView(TrayNetwork* tray, 407 TrayNetwork::MessageType message_type, 408 const NetworkMessages::Message& network_msg) 409 : tray_(tray), 410 message_type_(message_type) { 411 SetLayoutManager( 412 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); 413 414 if (!network_msg.title.empty()) { 415 views::Label* title = new views::Label(network_msg.title); 416 title->SetHorizontalAlignment(gfx::ALIGN_LEFT); 417 title->SetFont(title->font().DeriveFont(0, gfx::Font::BOLD)); 418 AddChildView(title); 419 } 420 421 if (!network_msg.message.empty()) { 422 views::Label* message = new views::Label(network_msg.message); 423 message->SetHorizontalAlignment(gfx::ALIGN_LEFT); 424 message->SetMultiLine(true); 425 message->SizeToFit(kTrayNotificationContentsWidth); 426 AddChildView(message); 427 } 428 429 if (!network_msg.links.empty()) { 430 for (size_t i = 0; i < network_msg.links.size(); ++i) { 431 views::Link* link = new views::Link(network_msg.links[i]); 432 link->set_id(i); 433 link->set_listener(this); 434 link->SetHorizontalAlignment(gfx::ALIGN_LEFT); 435 link->SetMultiLine(true); 436 link->SizeToFit(kTrayNotificationContentsWidth); 437 AddChildView(link); 438 } 439 } 440 } 441 442 virtual ~NetworkMessageView() { 443 } 444 445 // Overridden from views::LinkListener. 446 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE { 447 tray_->LinkClicked(message_type_, source->id()); 448 } 449 450 TrayNetwork::MessageType message_type() const { return message_type_; } 451 452 private: 453 TrayNetwork* tray_; 454 TrayNetwork::MessageType message_type_; 455 456 DISALLOW_COPY_AND_ASSIGN(NetworkMessageView); 457}; 458 459class NetworkNotificationView : public TrayNotificationView { 460 public: 461 explicit NetworkNotificationView(TrayNetwork* tray) 462 : TrayNotificationView(tray, 0) { 463 CreateMessageView(); 464 InitView(network_message_view_); 465 SetIconImage(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 466 GetMessageIcon(network_message_view_->message_type()))); 467 } 468 469 // Overridden from TrayNotificationView. 470 virtual void OnClose() OVERRIDE { 471 tray_network()->ClearNetworkMessage(network_message_view_->message_type()); 472 } 473 474 virtual void OnClickAction() OVERRIDE { 475 if (network_message_view_->message_type() != 476 TrayNetwork::MESSAGE_DATA_PROMO) 477 tray()->PopupDetailedView(0, true); 478 } 479 480 void Update() { 481 CreateMessageView(); 482 UpdateViewAndImage(network_message_view_, 483 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 484 GetMessageIcon(network_message_view_->message_type()))); 485 } 486 487 private: 488 TrayNetwork* tray_network() { 489 return static_cast<TrayNetwork*>(tray()); 490 } 491 492 void CreateMessageView() { 493 // Display the first (highest priority) message. 494 CHECK(!tray_network()->messages()->messages().empty()); 495 NetworkMessages::MessageMap::const_iterator iter = 496 tray_network()->messages()->messages().begin(); 497 network_message_view_ = 498 new NetworkMessageView(tray_network(), iter->first, iter->second); 499 } 500 501 tray::NetworkMessageView* network_message_view_; 502 503 DISALLOW_COPY_AND_ASSIGN(NetworkNotificationView); 504}; 505 506} // namespace tray 507 508TrayNetwork::TrayNetwork() 509 : tray_(NULL), 510 default_(NULL), 511 detailed_(NULL), 512 notification_(NULL), 513 messages_(new tray::NetworkMessages()), 514 request_wifi_view_(false) { 515} 516 517TrayNetwork::~TrayNetwork() { 518} 519 520views::View* TrayNetwork::CreateTrayView(user::LoginStatus status) { 521 CHECK(tray_ == NULL); 522 tray_ = new tray::NetworkTrayView(tray::LIGHT, true /*tray_icon*/); 523 return tray_; 524} 525 526views::View* TrayNetwork::CreateDefaultView(user::LoginStatus status) { 527 CHECK(default_ == NULL); 528 default_ = 529 new tray::NetworkDefaultView(this, status != user::LOGGED_IN_LOCKED); 530 return default_; 531} 532 533views::View* TrayNetwork::CreateDetailedView(user::LoginStatus status) { 534 CHECK(detailed_ == NULL); 535 // Clear any notifications when showing the detailed view. 536 messages_->messages().clear(); 537 HideNotificationView(); 538 if (request_wifi_view_) { 539 SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); 540 // The Wi-Fi state is not toggled yet at this point. 541 detailed_ = new tray::NetworkWifiDetailedView(!delegate->GetWifiEnabled()); 542 request_wifi_view_ = false; 543 } else { 544 detailed_ = new tray::NetworkListDetailedView( 545 status, IDS_ASH_STATUS_TRAY_NETWORK); 546 detailed_->Init(); 547 } 548 return detailed_; 549} 550 551views::View* TrayNetwork::CreateNotificationView(user::LoginStatus status) { 552 CHECK(notification_ == NULL); 553 if (messages_->messages().empty()) 554 return NULL; // Message has already been cleared. 555 notification_ = new tray::NetworkNotificationView(this); 556 return notification_; 557} 558 559void TrayNetwork::DestroyTrayView() { 560 tray_ = NULL; 561} 562 563void TrayNetwork::DestroyDefaultView() { 564 default_ = NULL; 565} 566 567void TrayNetwork::DestroyDetailedView() { 568 detailed_ = NULL; 569} 570 571void TrayNetwork::DestroyNotificationView() { 572 notification_ = NULL; 573} 574 575void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) { 576} 577 578void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 579 SetTrayImageItemBorder(tray_, alignment); 580} 581 582void TrayNetwork::OnNetworkRefresh(const NetworkIconInfo& info) { 583 if (tray_) 584 tray_->Update(info); 585 if (default_) 586 default_->Update(); 587 if (detailed_) 588 detailed_->Update(); 589} 590 591void TrayNetwork::SetNetworkMessage(NetworkTrayDelegate* delegate, 592 MessageType message_type, 593 const string16& title, 594 const string16& message, 595 const std::vector<string16>& links) { 596 messages_->messages()[message_type] = 597 tray::NetworkMessages::Message(delegate, title, message, links); 598 if (notification_) 599 notification_->Update(); 600 else 601 ShowNotificationView(); 602} 603 604void TrayNetwork::ClearNetworkMessage(MessageType message_type) { 605 messages_->messages().erase(message_type); 606 if (messages_->messages().empty()) { 607 HideNotificationView(); 608 return; 609 } 610 if (notification_) 611 notification_->Update(); 612 else 613 ShowNotificationView(); 614} 615 616void TrayNetwork::OnWillToggleWifi() { 617 if (!detailed_ || 618 detailed_->GetViewType() == tray::NetworkDetailedView::WIFI_VIEW) { 619 request_wifi_view_ = true; 620 PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); 621 } 622} 623 624void TrayNetwork::LinkClicked(MessageType message_type, int link_id) { 625 tray::NetworkMessages::MessageMap::const_iterator iter = 626 messages()->messages().find(message_type); 627 if (iter != messages()->messages().end() && iter->second.delegate) 628 iter->second.delegate->NotificationLinkClicked(link_id); 629} 630 631} // namespace internal 632} // namespace ash 633