Home | History | Annotate | Download | only in network
      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:
     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     ui::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     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 
     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::AXViewState* state) OVERRIDE {
    105     state->name = connection_status_string_;
    106     state->role = ui::AX_ROLE_BUTTON;
    107   }
    108 
    109   // ui::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::AX_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 
    143 class NetworkDefaultView : public TrayItemMore,
    144                            public ui::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     ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
    154   }
    155 
    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
    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:
    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 
    202   virtual ~NetworkWifiDetailedView() {
    203   }
    204 
    205   // Overridden from NetworkDetailedView:
    206 
    207   virtual void Init() OVERRIDE {
    208   }
    209 
    210   virtual NetworkDetailedView::DetailedViewType GetViewType() const OVERRIDE {
    211     return NetworkDetailedView::WIFI_VIEW;
    212   }
    213 
    214   virtual void ManagerChanged() OVERRIDE {
    215     Update();
    216   }
    217 
    218   virtual void NetworkListChanged() OVERRIDE {
    219     Update();
    220   }
    221 
    222   virtual void NetworkServiceChanged(
    223       const chromeos::NetworkState* network) OVERRIDE {
    224   }
    225 
    226  private:
    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 
    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 
    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 
    274 TrayNetwork::~TrayNetwork() {
    275   SystemTrayNotifier* notifier = Shell::GetInstance()->system_tray_notifier();
    276   notifier->RemoveNetworkObserver(this);
    277   notifier->RemoveNetworkPortalDetectorObserver(this);
    278 }
    279 
    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 
    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 
    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 
    315 void TrayNetwork::DestroyTrayView() {
    316   tray_ = NULL;
    317 }
    318 
    319 void TrayNetwork::DestroyDefaultView() {
    320   default_ = NULL;
    321 }
    322 
    323 void TrayNetwork::DestroyDetailedView() {
    324   detailed_ = NULL;
    325 }
    326 
    327 void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) {
    328 }
    329 
    330 void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
    331   if (tray_) {
    332     SetTrayImageItemBorder(tray_, alignment);
    333     tray_->UpdateAlignment(alignment);
    334   }
    335 }
    336 
    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 
    355 void TrayNetwork::OnCaptivePortalDetected(
    356     const std::string& /* service_path */) {
    357   NetworkStateChanged(false);
    358 }
    359 
    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 
    373 void TrayNetwork::NetworkServiceChanged(const chromeos::NetworkState* network) {
    374   if (detailed_)
    375     detailed_->NetworkServiceChanged(network);
    376 }
    377 
    378 }  // namespace ash
    379