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