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