1 // Copyright 2014 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 "ui/chromeos/network/network_list.h" 6 7 #include "chromeos/dbus/dbus_thread_manager.h" 8 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" 9 #include "chromeos/dbus/power_manager_client.h" 10 #include "chromeos/network/network_state.h" 11 #include "chromeos/network/network_state_handler.h" 12 #include "chromeos/network/network_state_handler_observer.h" 13 #include "grit/ui_chromeos_strings.h" 14 #include "ui/base/resource/resource_bundle.h" 15 #include "ui/chromeos/network/network_icon.h" 16 #include "ui/chromeos/network/network_icon_animation.h" 17 #include "ui/chromeos/network/network_info.h" 18 #include "ui/chromeos/network/network_list_delegate.h" 19 #include "ui/gfx/font.h" 20 #include "ui/views/controls/label.h" 21 #include "ui/views/view.h" 22 23 using chromeos::NetworkHandler; 24 using chromeos::NetworkStateHandler; 25 using chromeos::NetworkTypePattern; 26 27 namespace ui { 28 29 // NetworkListView: 30 31 NetworkListView::NetworkListView(NetworkListDelegate* delegate) 32 : delegate_(delegate), 33 content_(NULL), 34 scanning_view_(NULL), 35 no_wifi_networks_view_(NULL), 36 no_cellular_networks_view_(NULL) { 37 CHECK(delegate); 38 } 39 40 NetworkListView::~NetworkListView() { 41 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 42 } 43 44 void NetworkListView::UpdateNetworkList() { 45 CHECK(content_); 46 NetworkStateHandler::NetworkStateList network_list; 47 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 48 handler->GetVisibleNetworkList(&network_list); 49 UpdateNetworks(network_list); 50 UpdateNetworkListInternal(); 51 } 52 53 bool NetworkListView::IsViewInList(views::View* view, 54 std::string* service_path) const { 55 std::map<views::View*, std::string>::const_iterator found = 56 network_map_.find(view); 57 if (found == network_map_.end()) 58 return false; 59 *service_path = found->second; 60 return true; 61 } 62 63 void NetworkListView::UpdateNetworks( 64 const NetworkStateHandler::NetworkStateList& networks) { 65 network_list_.clear(); 66 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); 67 for (NetworkStateHandler::NetworkStateList::const_iterator iter = 68 networks.begin(); 69 iter != networks.end(); 70 ++iter) { 71 const chromeos::NetworkState* network = *iter; 72 if (!pattern.MatchesType(network->type())) 73 continue; 74 NetworkInfo* info = new NetworkInfo(network->path()); 75 network_list_.push_back(info); 76 } 77 } 78 79 void NetworkListView::UpdateNetworkListInternal() { 80 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 81 82 // First, update state for all networks 83 bool animating = false; 84 for (size_t i = 0; i < network_list_.size(); ++i) { 85 NetworkInfo* info = network_list_[i]; 86 const chromeos::NetworkState* network = 87 handler->GetNetworkState(info->service_path); 88 if (!network) 89 continue; 90 info->image = 91 network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); 92 info->label = 93 network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST); 94 info->highlight = 95 network->IsConnectedState() || network->IsConnectingState(); 96 info->disable = 97 network->activation_state() == shill::kActivationStateActivating; 98 if (!animating && network->IsConnectingState()) 99 animating = true; 100 } 101 102 if (animating) 103 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); 104 else 105 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); 106 107 // Get the updated list entries 108 network_map_.clear(); 109 std::set<std::string> new_service_paths; 110 bool needs_relayout = UpdateNetworkListEntries(&new_service_paths); 111 112 // Remove old children 113 std::set<std::string> remove_service_paths; 114 for (ServicePathMap::const_iterator it = service_path_map_.begin(); 115 it != service_path_map_.end(); 116 ++it) { 117 if (new_service_paths.find(it->first) == new_service_paths.end()) { 118 remove_service_paths.insert(it->first); 119 network_map_.erase(it->second); 120 content_->RemoveChildView(it->second); 121 needs_relayout = true; 122 } 123 } 124 125 for (std::set<std::string>::const_iterator remove_it = 126 remove_service_paths.begin(); 127 remove_it != remove_service_paths.end(); 128 ++remove_it) { 129 service_path_map_.erase(*remove_it); 130 } 131 132 if (needs_relayout) { 133 views::View* selected_view = NULL; 134 for (ServicePathMap::const_iterator iter = service_path_map_.begin(); 135 iter != service_path_map_.end(); 136 ++iter) { 137 if (delegate_->IsViewHovered(iter->second)) { 138 selected_view = iter->second; 139 break; 140 } 141 } 142 content_->SizeToPreferredSize(); 143 delegate_->RelayoutScrollList(); 144 if (selected_view) 145 content_->ScrollRectToVisible(selected_view->bounds()); 146 } 147 } 148 149 bool NetworkListView::UpdateNetworkListEntries( 150 std::set<std::string>* new_service_paths) { 151 bool needs_relayout = false; 152 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 153 154 // Insert child views 155 int index = 0; 156 157 // Highlighted networks 158 for (size_t i = 0; i < network_list_.size(); ++i) { 159 const NetworkInfo* info = network_list_[i]; 160 if (info->highlight) { 161 if (UpdateNetworkChild(index++, info)) 162 needs_relayout = true; 163 new_service_paths->insert(info->service_path); 164 } 165 } 166 167 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); 168 if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) { 169 // Cellular initializing 170 int message_id = network_icon::GetCellularUninitializedMsg(); 171 if (!message_id && 172 handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && 173 !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) { 174 message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS; 175 } 176 if (UpdateInfoLabel(message_id, index, &no_cellular_networks_view_)) 177 needs_relayout = true; 178 if (message_id) 179 ++index; 180 } 181 182 if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) { 183 // "Wifi Enabled / Disabled" 184 int message_id = 0; 185 if (network_list_.empty()) { 186 message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()) 187 ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED 188 : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; 189 } 190 if (UpdateInfoLabel(message_id, index, &no_wifi_networks_view_)) 191 needs_relayout = true; 192 if (message_id) 193 ++index; 194 195 // "Wifi Scanning" 196 message_id = 0; 197 if (handler->GetScanningByType(NetworkTypePattern::WiFi())) 198 message_id = IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE; 199 if (UpdateInfoLabel(message_id, index, &scanning_view_)) 200 needs_relayout = true; 201 if (message_id) 202 ++index; 203 } 204 205 // Un-highlighted networks 206 for (size_t i = 0; i < network_list_.size(); ++i) { 207 const NetworkInfo* info = network_list_[i]; 208 if (!info->highlight) { 209 if (UpdateNetworkChild(index++, info)) 210 needs_relayout = true; 211 new_service_paths->insert(info->service_path); 212 } 213 } 214 215 // No networks or other messages (fallback) 216 if (index == 0) { 217 int message_id = 0; 218 if (pattern.Equals(NetworkTypePattern::VPN())) 219 message_id = IDS_ASH_STATUS_TRAY_NETWORK_NO_VPN; 220 else 221 message_id = IDS_ASH_STATUS_TRAY_NO_NETWORKS; 222 if (UpdateInfoLabel(message_id, index, &scanning_view_)) 223 needs_relayout = true; 224 } 225 226 return needs_relayout; 227 } 228 229 bool NetworkListView::UpdateNetworkChild(int index, const NetworkInfo* info) { 230 bool needs_relayout = false; 231 views::View* container = NULL; 232 ServicePathMap::const_iterator found = 233 service_path_map_.find(info->service_path); 234 if (found == service_path_map_.end()) { 235 container = delegate_->CreateViewForNetwork(*info); 236 content_->AddChildViewAt(container, index); 237 needs_relayout = true; 238 } else { 239 container = found->second; 240 container->RemoveAllChildViews(true); 241 delegate_->UpdateViewForNetwork(container, *info); 242 container->Layout(); 243 container->SchedulePaint(); 244 needs_relayout = PlaceViewAtIndex(container, index); 245 } 246 if (info->disable) 247 container->SetEnabled(false); 248 network_map_[container] = info->service_path; 249 service_path_map_[info->service_path] = container; 250 return needs_relayout; 251 } 252 253 bool NetworkListView::PlaceViewAtIndex(views::View* view, int index) { 254 if (content_->child_at(index) == view) 255 return false; 256 content_->ReorderChildView(view, index); 257 return true; 258 } 259 260 bool NetworkListView::UpdateInfoLabel(int message_id, 261 int index, 262 views::Label** label) { 263 CHECK(label); 264 bool needs_relayout = false; 265 if (message_id) { 266 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 267 base::string16 text = rb.GetLocalizedString(message_id); 268 if (!*label) { 269 *label = delegate_->CreateInfoLabel(); 270 (*label)->SetText(text); 271 content_->AddChildViewAt(*label, index); 272 needs_relayout = true; 273 } else { 274 (*label)->SetText(text); 275 needs_relayout = PlaceViewAtIndex(*label, index); 276 } 277 } else if (*label) { 278 content_->RemoveChildView(*label); 279 delete *label; 280 *label = NULL; 281 needs_relayout = true; 282 } 283 return needs_relayout; 284 } 285 286 void NetworkListView::NetworkIconChanged() { 287 UpdateNetworkList(); 288 } 289 290 } // namespace ui 291