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