tray_network.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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_icon_animation.h" 11#include "ash/system/chromeos/network/network_state_list_detailed_view.h" 12#include "ash/system/chromeos/network/tray_network_state_observer.h" 13#include "ash/system/tray/system_tray.h" 14#include "ash/system/tray/system_tray_delegate.h" 15#include "ash/system/tray/system_tray_notifier.h" 16#include "ash/system/tray/tray_constants.h" 17#include "ash/system/tray/tray_item_more.h" 18#include "ash/system/tray/tray_item_view.h" 19#include "ash/system/tray/tray_utils.h" 20#include "base/command_line.h" 21#include "base/strings/utf_string_conversions.h" 22#include "chromeos/network/network_state.h" 23#include "chromeos/network/network_state_handler.h" 24#include "chromeos/network/shill_property_util.h" 25#include "grit/ash_resources.h" 26#include "grit/ash_strings.h" 27#include "third_party/cros_system_api/dbus/service_constants.h" 28#include "ui/base/accessibility/accessible_view_state.h" 29#include "ui/base/l10n/l10n_util.h" 30#include "ui/base/resource/resource_bundle.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 internal { 44 45namespace tray { 46 47class NetworkTrayView : public TrayItemView, 48 public network_icon::AnimationObserver { 49 public: 50 explicit NetworkTrayView(TrayNetwork* network_tray) 51 : TrayItemView(network_tray), 52 network_tray_(network_tray) { 53 SetLayoutManager( 54 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); 55 56 image_view_ = new views::ImageView; 57 AddChildView(image_view_); 58 59 UpdateNetworkStateHandlerIcon(); 60 } 61 62 virtual ~NetworkTrayView() { 63 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 64 } 65 66 virtual const char* GetClassName() const OVERRIDE { 67 return "NetworkTrayView"; 68 } 69 70 void UpdateNetworkStateHandlerIcon() { 71 NetworkStateHandler* handler = 72 NetworkHandler::Get()->network_state_handler(); 73 gfx::ImageSkia image; 74 base::string16 name; 75 bool animating = false; 76 network_icon::GetDefaultNetworkImageAndLabel( 77 network_icon::ICON_TYPE_TRAY, &image, &name, &animating); 78 bool show_in_tray = !image.isNull(); 79 UpdateIcon(show_in_tray, image); 80 if (animating) 81 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 82 else 83 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(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::AccessibleViewState* state) OVERRIDE { 105 state->name = connection_status_string_; 106 state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON; 107 } 108 109 // 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::AccessibilityTypes::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 143class NetworkDefaultView : public TrayItemMore, 144 public 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 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 154 } 155 156 void Update() { 157 gfx::ImageSkia image; 158 base::string16 label; 159 bool animating = false; 160 network_icon::GetDefaultNetworkImageAndLabel( 161 network_icon::ICON_TYPE_DEFAULT_VIEW, &image, &label, &animating); 162 if (animating) 163 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 164 else 165 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 166 SetImage(&image); 167 SetLabel(label); 168 SetAccessibleName(label); 169 } 170 171 // 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 Shell::GetInstance()->system_tray_notifier()->AddNetworkObserver(this); 269} 270 271TrayNetwork::~TrayNetwork() { 272 Shell::GetInstance()->system_tray_notifier()->RemoveNetworkObserver(this); 273} 274 275views::View* TrayNetwork::CreateTrayView(user::LoginStatus status) { 276 CHECK(tray_ == NULL); 277 if (!chromeos::NetworkHandler::IsInitialized()) 278 return NULL; 279 tray_ = new tray::NetworkTrayView(this); 280 return tray_; 281} 282 283views::View* TrayNetwork::CreateDefaultView(user::LoginStatus status) { 284 CHECK(default_ == NULL); 285 if (!chromeos::NetworkHandler::IsInitialized()) 286 return NULL; 287 CHECK(tray_ != NULL); 288 default_ = new tray::NetworkDefaultView( 289 this, status != user::LOGGED_IN_LOCKED); 290 return default_; 291} 292 293views::View* TrayNetwork::CreateDetailedView(user::LoginStatus status) { 294 CHECK(detailed_ == NULL); 295 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 296 ash::UMA_STATUS_AREA_DETAILED_NETWORK_VIEW); 297 if (!chromeos::NetworkHandler::IsInitialized()) 298 return NULL; 299 if (request_wifi_view_) { 300 detailed_ = new tray::NetworkWifiDetailedView(this); 301 request_wifi_view_ = false; 302 } else { 303 detailed_ = new tray::NetworkStateListDetailedView( 304 this, tray::NetworkStateListDetailedView::LIST_TYPE_NETWORK, status); 305 detailed_->Init(); 306 } 307 return detailed_; 308} 309 310void TrayNetwork::DestroyTrayView() { 311 tray_ = NULL; 312} 313 314void TrayNetwork::DestroyDefaultView() { 315 default_ = NULL; 316} 317 318void TrayNetwork::DestroyDetailedView() { 319 detailed_ = NULL; 320} 321 322void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) { 323} 324 325void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { 326 if (tray_) { 327 SetTrayImageItemBorder(tray_, alignment); 328 tray_->UpdateAlignment(alignment); 329 } 330} 331 332void TrayNetwork::RequestToggleWifi() { 333 // This will always be triggered by a user action (e.g. keyboard shortcut) 334 if (!detailed_ || 335 detailed_->GetViewType() == tray::NetworkDetailedView::WIFI_VIEW) { 336 request_wifi_view_ = true; 337 PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); 338 } 339 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 340 bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()); 341 Shell::GetInstance()->metrics()->RecordUserMetricsAction( 342 enabled ? 343 ash::UMA_STATUS_AREA_DISABLE_WIFI : 344 ash::UMA_STATUS_AREA_ENABLE_WIFI); 345 handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), 346 !enabled, 347 chromeos::network_handler::ErrorCallback()); 348} 349 350void TrayNetwork::NetworkStateChanged(bool list_changed) { 351 if (tray_) 352 tray_->UpdateNetworkStateHandlerIcon(); 353 if (default_) 354 default_->Update(); 355 if (detailed_) { 356 if (list_changed) 357 detailed_->NetworkListChanged(); 358 else 359 detailed_->ManagerChanged(); 360 } 361} 362 363void TrayNetwork::NetworkServiceChanged(const chromeos::NetworkState* network) { 364 if (detailed_) 365 detailed_->NetworkServiceChanged(network); 366} 367 368} // namespace internal 369} // namespace ash 370