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_vpn.h"
6
7#include "ash/metrics/user_metrics_recorder.h"
8#include "ash/session/session_state_delegate.h"
9#include "ash/shell.h"
10#include "ash/system/chromeos/network/network_state_list_detailed_view.h"
11#include "ash/system/tray/system_tray.h"
12#include "ash/system/tray/system_tray_delegate.h"
13#include "ash/system/tray/tray_constants.h"
14#include "ash/system/tray/tray_item_more.h"
15#include "ash/system/tray/tray_popup_label_button.h"
16#include "chromeos/network/network_state.h"
17#include "chromeos/network/network_state_handler.h"
18#include "grit/ash_strings.h"
19#include "grit/ui_chromeos_strings.h"
20#include "third_party/cros_system_api/dbus/service_constants.h"
21#include "ui/base/l10n/l10n_util.h"
22#include "ui/chromeos/network/network_icon.h"
23#include "ui/chromeos/network/network_icon_animation.h"
24
25using chromeos::NetworkHandler;
26using chromeos::NetworkState;
27using chromeos::NetworkStateHandler;
28using chromeos::NetworkTypePattern;
29
30namespace ash {
31namespace tray {
32
33class VpnDefaultView : public TrayItemMore,
34                       public ui::network_icon::AnimationObserver {
35 public:
36  VpnDefaultView(SystemTrayItem* owner, bool show_more)
37      : TrayItemMore(owner, show_more) {
38    Update();
39  }
40
41  virtual ~VpnDefaultView() {
42    ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
43  }
44
45  static bool ShouldShow() {
46    // Do not show VPN line in uber tray bubble if VPN is not configured.
47    NetworkStateHandler* handler =
48        NetworkHandler::Get()->network_state_handler();
49    const NetworkState* vpn =
50        handler->FirstNetworkByType(NetworkTypePattern::VPN());
51    return vpn != NULL;
52  }
53
54  void Update() {
55    gfx::ImageSkia image;
56    base::string16 label;
57    bool animating = false;
58    GetNetworkStateHandlerImageAndLabel(&image, &label, &animating);
59    if (animating)
60      ui::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
61    else
62      ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(
63          this);
64    SetImage(&image);
65    SetLabel(label);
66    SetAccessibleName(label);
67  }
68
69  // ui::network_icon::AnimationObserver
70  virtual void NetworkIconChanged() OVERRIDE {
71    Update();
72  }
73
74 private:
75  void GetNetworkStateHandlerImageAndLabel(gfx::ImageSkia* image,
76                                           base::string16* label,
77                                           bool* animating) {
78    NetworkStateHandler* handler =
79        NetworkHandler::Get()->network_state_handler();
80    const NetworkState* vpn =
81        handler->FirstNetworkByType(NetworkTypePattern::VPN());
82    if (!vpn || (vpn->connection_state() == shill::kStateIdle)) {
83      *image = ui::network_icon::GetImageForDisconnectedNetwork(
84          ui::network_icon::ICON_TYPE_DEFAULT_VIEW, shill::kTypeVPN);
85      if (label) {
86        *label = l10n_util::GetStringUTF16(
87            IDS_ASH_STATUS_TRAY_VPN_DISCONNECTED);
88      }
89      *animating = false;
90      return;
91    }
92    *animating = vpn->IsConnectingState();
93    *image = ui::network_icon::GetImageForNetwork(
94        vpn, ui::network_icon::ICON_TYPE_DEFAULT_VIEW);
95    if (label) {
96      *label = ui::network_icon::GetLabelForNetwork(
97          vpn, ui::network_icon::ICON_TYPE_DEFAULT_VIEW);
98    }
99  }
100
101  DISALLOW_COPY_AND_ASSIGN(VpnDefaultView);
102};
103
104}  // namespace tray
105
106TrayVPN::TrayVPN(SystemTray* system_tray)
107    : SystemTrayItem(system_tray),
108      default_(NULL),
109      detailed_(NULL) {
110  network_state_observer_.reset(new TrayNetworkStateObserver(this));
111}
112
113TrayVPN::~TrayVPN() {
114}
115
116views::View* TrayVPN::CreateTrayView(user::LoginStatus status) {
117  return NULL;
118}
119
120views::View* TrayVPN::CreateDefaultView(user::LoginStatus status) {
121  CHECK(default_ == NULL);
122  if (!chromeos::NetworkHandler::IsInitialized())
123    return NULL;
124  if (status == user::LOGGED_IN_NONE)
125    return NULL;
126  if (!tray::VpnDefaultView::ShouldShow())
127    return NULL;
128
129  bool userAddingRunning = ash::Shell::GetInstance()
130                               ->session_state_delegate()
131                               ->IsInSecondaryLoginScreen();
132
133  default_ = new tray::VpnDefaultView(
134      this, status != user::LOGGED_IN_LOCKED && !userAddingRunning);
135
136  return default_;
137}
138
139views::View* TrayVPN::CreateDetailedView(user::LoginStatus status) {
140  CHECK(detailed_ == NULL);
141  if (!chromeos::NetworkHandler::IsInitialized())
142    return NULL;
143
144  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
145      ash::UMA_STATUS_AREA_DETAILED_VPN_VIEW);
146  detailed_ = new tray::NetworkStateListDetailedView(
147      this, tray::NetworkStateListDetailedView::LIST_TYPE_VPN, status);
148  detailed_->Init();
149  return detailed_;
150}
151
152void TrayVPN::DestroyTrayView() {
153}
154
155void TrayVPN::DestroyDefaultView() {
156  default_ = NULL;
157}
158
159void TrayVPN::DestroyDetailedView() {
160  detailed_ = NULL;
161}
162
163void TrayVPN::UpdateAfterLoginStatusChange(user::LoginStatus status) {
164}
165
166void TrayVPN::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
167}
168
169void TrayVPN::NetworkStateChanged(bool list_changed) {
170  if (default_)
171    default_->Update();
172  if (detailed_) {
173    if (list_changed)
174      detailed_->NetworkListChanged();
175    else
176      detailed_->ManagerChanged();
177  }
178}
179
180void TrayVPN::NetworkServiceChanged(const chromeos::NetworkState* network) {
181  if (detailed_)
182    detailed_->NetworkServiceChanged(network);
183}
184
185}  // namespace ash
186