tray_network.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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/ash_switches.h" 8#include "ash/metrics/user_metrics_recorder.h" 9#include "ash/shell.h" 10#include "ash/system/chromeos/network/network_state_list_detailed_view.h" 11#include "ash/system/chromeos/network/tray_network_state_observer.h" 12#include "ash/system/tray/system_tray.h" 13#include "ash/system/tray/system_tray_delegate.h" 14#include "ash/system/tray/system_tray_notifier.h" 15#include "ash/system/tray/tray_constants.h" 16#include "ash/system/tray/tray_item_more.h" 17#include "ash/system/tray/tray_item_view.h" 18#include "ash/system/tray/tray_utils.h" 19#include "base/command_line.h" 20#include "base/strings/utf_string_conversions.h" 21#include "chromeos/network/network_state.h" 22#include "chromeos/network/network_state_handler.h" 23#include "grit/ash_resources.h" 24#include "grit/ash_strings.h" 25#include "grit/ui_chromeos_strings.h" 26#include "third_party/cros_system_api/dbus/service_constants.h" 27#include "ui/accessibility/ax_view_state.h" 28#include "ui/base/l10n/l10n_util.h" 29#include "ui/base/resource/resource_bundle.h" 30#include "ui/chromeos/network/network_icon_animation.h" 31#include "ui/views/controls/image_view.h" 32#include "ui/views/controls/link.h" 33#include "ui/views/controls/link_listener.h" 34#include "ui/views/layout/box_layout.h" 35#include "ui/views/widget/widget.h" 36 37using chromeos::NetworkHandler; 38using chromeos::NetworkState; 39using chromeos::NetworkStateHandler; 40using chromeos::NetworkTypePattern; 41 42namespace ash { 43namespace tray { 44 45class NetworkTrayView : public TrayItemView, 46 public ui::network_icon::AnimationObserver { 47 public: 48 explicit NetworkTrayView(TrayNetwork* network_tray) 49 : TrayItemView(network_tray), 50 network_tray_(network_tray) { 51 SetLayoutManager( 52 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); 53 54 image_view_ = new views::ImageView; 55 AddChildView(image_view_); 56 57 UpdateNetworkStateHandlerIcon(); 58 } 59 60 virtual ~NetworkTrayView() { 61 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 62 } 63 64 virtual const char* GetClassName() const OVERRIDE { 65 return "NetworkTrayView"; 66 } 67 68 void UpdateNetworkStateHandlerIcon() { 69 NetworkStateHandler* handler = 70 NetworkHandler::Get()->network_state_handler(); 71 gfx::ImageSkia image; 72 base::string16 name; 73 bool animating = false; 74 ui::network_icon::GetDefaultNetworkImageAndLabel( 75 ui::network_icon::ICON_TYPE_TRAY, &image, &name, &animating); 76 bool show_in_tray = !image.isNull(); 77 UpdateIcon(show_in_tray, image); 78 if (animating) 79 ui::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 80 else 81 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver( 82 this); 83 // Update accessibility. 84 const NetworkState* connected_network = 85 handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); 86 if (connected_network) { 87 UpdateConnectionStatus( 88 base::UTF8ToUTF16(connected_network->name()), true); 89 } else { 90 UpdateConnectionStatus(base::string16(), false); 91 } 92 } 93 94 void UpdateAlignment(ShelfAlignment alignment) { 95 SetLayoutManager(new views::BoxLayout( 96 alignment == SHELF_ALIGNMENT_BOTTOM ? 97 views::BoxLayout::kHorizontal : views::BoxLayout::kVertical, 98 0, 0, 0)); 99 Layout(); 100 } 101 102 // views::View override. 103 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE { 104 state->name = connection_status_string_; 105 state->role = ui::AX_ROLE_BUTTON; 106 } 107 108 // ui::network_icon::AnimationObserver 109 virtual void NetworkIconChanged() OVERRIDE { 110 UpdateNetworkStateHandlerIcon(); 111 } 112 113 private: 114 // Updates connection status and notifies accessibility event when necessary. 115 void UpdateConnectionStatus(const base::string16& network_name, 116 bool connected) { 117 base::string16 new_connection_status_string; 118 if (connected) { 119 new_connection_status_string = l10n_util::GetStringFUTF16( 120 IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name); 121 } 122 if (new_connection_status_string != connection_status_string_) { 123 connection_status_string_ = new_connection_status_string; 124 if(!connection_status_string_.empty()) 125 NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); 126 } 127 } 128 129 void UpdateIcon(bool tray_icon_visible, const gfx::ImageSkia& image) { 130 image_view_->SetImage(image); 131 SetVisible(tray_icon_visible); 132 SchedulePaint(); 133 } 134 135 TrayNetwork* network_tray_; 136 views::ImageView* image_view_; 137 base::string16 connection_status_string_; 138 139 DISALLOW_COPY_AND_ASSIGN(NetworkTrayView); 140}; 141 142class NetworkDefaultView : public TrayItemMore, 143 public ui::network_icon::AnimationObserver { 144 public: 145 NetworkDefaultView(TrayNetwork* network_tray, bool show_more) 146 : TrayItemMore(network_tray, show_more), 147 network_tray_(network_tray) { 148 Update(); 149 } 150 151 virtual ~NetworkDefaultView() { 152 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 153 } 154 155 void Update() { 156 gfx::ImageSkia image; 157 base::string16 label; 158 bool animating = false; 159 ui::network_icon::GetDefaultNetworkImageAndLabel( 160 ui::network_icon::ICON_TYPE_DEFAULT_VIEW, &image, &label, &animating); 161 if (animating) 162 ui::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 163 else 164 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver( 165 this); 166 SetImage(&image); 167 SetLabel(label); 168 SetAccessibleName(label); 169 } 170 171 // ui::network_icon::AnimationObserver 172 virtual void NetworkIconChanged() OVERRIDE { 173 Update(); 174 } 175 176 private: 177 TrayNetwork* network_tray_; 178 179 DISALLOW_COPY_AND_ASSIGN(NetworkDefaultView); 180}; 181 182class NetworkWifiDetailedView : public NetworkDetailedView { 183 public: 184 explicit NetworkWifiDetailedView(SystemTrayItem* owner) 185 : NetworkDetailedView(owner) { 186 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 187 kTrayPopupPaddingHorizontal, 188 10, 189 kTrayPopupPaddingBetweenItems)); 190 image_view_ = new views::ImageView; 191 AddChildView(image_view_); 192 193 label_view_ = new views::Label(); 194 label_view_->SetMultiLine(true); 195 label_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 196 AddChildView(label_view_); 197 198 Update(); 199 } 200 201 virtual ~NetworkWifiDetailedView() { 202 } 203 204 // Overridden from NetworkDetailedView: 205 206 virtual void Init() OVERRIDE { 207 } 208 209 virtual NetworkDetailedView::DetailedViewType GetViewType() const OVERRIDE { 210 return NetworkDetailedView::WIFI_VIEW; 211 } 212 213 virtual void ManagerChanged() OVERRIDE { 214 Update(); 215 } 216 217 virtual void NetworkListChanged() OVERRIDE { 218 Update(); 219 } 220 221 virtual void NetworkServiceChanged( 222 const chromeos::NetworkState* network) OVERRIDE { 223 } 224 225 private: 226 virtual void Layout() OVERRIDE { 227 // Center both views vertically. 228 views::View::Layout(); 229 image_view_->SetY( 230 (height() - image_view_->GetPreferredSize().height()) / 2); 231 label_view_->SetY( 232 (height() - label_view_->GetPreferredSize().height()) / 2); 233 } 234 235 void Update() { 236 bool wifi_enabled = 237 NetworkHandler::Get()->network_state_handler()->IsTechnologyEnabled( 238 NetworkTypePattern::WiFi()); 239 const int image_id = wifi_enabled ? 240 IDR_AURA_UBER_TRAY_WIFI_ENABLED : IDR_AURA_UBER_TRAY_WIFI_DISABLED; 241 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 242 image_view_->SetImage(bundle.GetImageNamed(image_id).ToImageSkia()); 243 244 const int string_id = wifi_enabled ? 245 IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED : 246 IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; 247 label_view_->SetText(bundle.GetLocalizedString(string_id)); 248 label_view_->SizeToFit(kTrayPopupMinWidth - 249 kTrayPopupPaddingHorizontal * 2 - kTrayPopupPaddingBetweenItems - 250 kTrayPopupDetailsIconWidth); 251 } 252 253 views::ImageView* image_view_; 254 views::Label* label_view_; 255 256 DISALLOW_COPY_AND_ASSIGN(NetworkWifiDetailedView); 257}; 258 259} // namespace tray 260 261TrayNetwork::TrayNetwork(SystemTray* system_tray) 262 : SystemTrayItem(system_tray), 263 tray_(NULL), 264 default_(NULL), 265 detailed_(NULL), 266 request_wifi_view_(false) { 267 network_state_observer_.reset(new TrayNetworkStateObserver(this)); 268 SystemTrayNotifier* notifier = Shell::GetInstance()->system_tray_notifier(); 269 notifier->AddNetworkObserver(this); 270 notifier->AddNetworkPortalDetectorObserver(this); 271} 272 273TrayNetwork::~TrayNetwork() { 274 SystemTrayNotifier* notifier = Shell::GetInstance()->system_tray_notifier(); 275 notifier->RemoveNetworkObserver(this); 276 notifier->RemoveNetworkPortalDetectorObserver(this); 277} 278 279views::View* TrayNetwork::CreateTrayView(user::LoginStatus status) { 280 CHECK(tray_ == NULL); 281 if (!chromeos::NetworkHandler::IsInitialized()) 282 return NULL; 283 tray_ = new tray::NetworkTrayView(this); 284 return tray_; 285} 286 287views::View* TrayNetwork::CreateDefaultView(user::LoginStatus status) { 288 CHECK(default_ == NULL); 289 if (!chromeos::NetworkHandler::IsInitialized()) 290 return NULL; 291 CHECK(tray_ != NULL); 292 default_ = new tray::NetworkDefaultView( 293 this, status != user::LOGGED_IN_LOCKED); 294 return default_; 295} 296 297views::View* TrayNetwork::CreateDetailedView(user::LoginStatus status) { 298 CHECK(detailed_ == NULL); 299 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 300 ash::UMA_STATUS_AREA_DETAILED_NETWORK_VIEW); 301 if (!chromeos::NetworkHandler::IsInitialized()) 302 return NULL; 303 if (request_wifi_view_) { 304 detailed_ = new tray::NetworkWifiDetailedView(this); 305 request_wifi_view_ = false; 306 } else { 307 detailed_ = new tray::NetworkStateListDetailedView( 308 this, tray::NetworkStateListDetailedView::LIST_TYPE_NETWORK, status); 309 detailed_->Init(); 310 } 311 return detailed_; 312} 313 314void TrayNetwork::DestroyTrayView() { 315 tray_ = NULL; 316} 317 318void TrayNetwork::DestroyDefaultView() { 319 default_ = NULL; 320} 321 322void TrayNetwork::DestroyDetailedView() { 323 detailed_ = NULL; 324} 325 326void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) { 327} 328 329void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 330 if (tray_) { 331 SetTrayImageItemBorder(tray_, alignment); 332 tray_->UpdateAlignment(alignment); 333 } 334} 335 336void TrayNetwork::RequestToggleWifi() { 337 // This will always be triggered by a user action (e.g. keyboard shortcut) 338 if (!detailed_ || 339 detailed_->GetViewType() == tray::NetworkDetailedView::WIFI_VIEW) { 340 request_wifi_view_ = true; 341 PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); 342 } 343 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 344 bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()); 345 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 346 enabled ? 347 ash::UMA_STATUS_AREA_DISABLE_WIFI : 348 ash::UMA_STATUS_AREA_ENABLE_WIFI); 349 handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), 350 !enabled, 351 chromeos::network_handler::ErrorCallback()); 352} 353 354void TrayNetwork::OnCaptivePortalDetected( 355 const std::string& /* service_path */) { 356 NetworkStateChanged(false); 357} 358 359void TrayNetwork::NetworkStateChanged(bool list_changed) { 360 if (tray_) 361 tray_->UpdateNetworkStateHandlerIcon(); 362 if (default_) 363 default_->Update(); 364 if (detailed_) { 365 if (list_changed) 366 detailed_->NetworkListChanged(); 367 else 368 detailed_->ManagerChanged(); 369 } 370} 371 372void TrayNetwork::NetworkServiceChanged(const chromeos::NetworkState* network) { 373 if (detailed_) 374 detailed_->NetworkServiceChanged(network); 375} 376 377} // namespace ash 378