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