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