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:
NetworkTrayView(TrayNetwork * network_tray)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
~NetworkTrayView()61 virtual ~NetworkTrayView() {
62 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
63 }
64
GetClassName() const65 virtual const char* GetClassName() const OVERRIDE {
66 return "NetworkTrayView";
67 }
68
UpdateNetworkStateHandlerIcon()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
UpdateAlignment(ShelfAlignment alignment)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.
GetAccessibleState(ui::AXViewState * state)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
NetworkIconChanged()110 virtual void NetworkIconChanged() OVERRIDE {
111 UpdateNetworkStateHandlerIcon();
112 }
113
114 private:
115 // Updates connection status and notifies accessibility event when necessary.
UpdateConnectionStatus(const base::string16 & network_name,bool connected)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
UpdateIcon(bool tray_icon_visible,const gfx::ImageSkia & image)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:
NetworkDefaultView(TrayNetwork * network_tray,bool show_more)146 NetworkDefaultView(TrayNetwork* network_tray, bool show_more)
147 : TrayItemMore(network_tray, show_more),
148 network_tray_(network_tray) {
149 Update();
150 }
151
~NetworkDefaultView()152 virtual ~NetworkDefaultView() {
153 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
154 }
155
Update()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
NetworkIconChanged()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:
NetworkWifiDetailedView(SystemTrayItem * owner)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
~NetworkWifiDetailedView()202 virtual ~NetworkWifiDetailedView() {
203 }
204
205 // Overridden from NetworkDetailedView:
206
Init()207 virtual void Init() OVERRIDE {
208 }
209
GetViewType() const210 virtual NetworkDetailedView::DetailedViewType GetViewType() const OVERRIDE {
211 return NetworkDetailedView::WIFI_VIEW;
212 }
213
ManagerChanged()214 virtual void ManagerChanged() OVERRIDE {
215 Update();
216 }
217
NetworkListChanged()218 virtual void NetworkListChanged() OVERRIDE {
219 Update();
220 }
221
NetworkServiceChanged(const chromeos::NetworkState * network)222 virtual void NetworkServiceChanged(
223 const chromeos::NetworkState* network) OVERRIDE {
224 }
225
226 private:
Layout()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
Update()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
TrayNetwork(SystemTray * system_tray)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
~TrayNetwork()274 TrayNetwork::~TrayNetwork() {
275 SystemTrayNotifier* notifier = Shell::GetInstance()->system_tray_notifier();
276 notifier->RemoveNetworkObserver(this);
277 notifier->RemoveNetworkPortalDetectorObserver(this);
278 }
279
CreateTrayView(user::LoginStatus status)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
CreateDefaultView(user::LoginStatus status)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
CreateDetailedView(user::LoginStatus status)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
DestroyTrayView()315 void TrayNetwork::DestroyTrayView() {
316 tray_ = NULL;
317 }
318
DestroyDefaultView()319 void TrayNetwork::DestroyDefaultView() {
320 default_ = NULL;
321 }
322
DestroyDetailedView()323 void TrayNetwork::DestroyDetailedView() {
324 detailed_ = NULL;
325 }
326
UpdateAfterLoginStatusChange(user::LoginStatus status)327 void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) {
328 }
329
UpdateAfterShelfAlignmentChange(ShelfAlignment alignment)330 void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
331 if (tray_) {
332 SetTrayImageItemBorder(tray_, alignment);
333 tray_->UpdateAlignment(alignment);
334 }
335 }
336
RequestToggleWifi()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
OnCaptivePortalDetected(const std::string &)355 void TrayNetwork::OnCaptivePortalDetected(
356 const std::string& /* service_path */) {
357 NetworkStateChanged(false);
358 }
359
NetworkStateChanged(bool list_changed)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
NetworkServiceChanged(const chromeos::NetworkState * network)373 void TrayNetwork::NetworkServiceChanged(const chromeos::NetworkState* network) {
374 if (detailed_)
375 detailed_->NetworkServiceChanged(network);
376 }
377
378 } // namespace ash
379