Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: ui/chromeos/network/network_list_md.cc

Issue 2342793005: [ash-md] Adds Wi-Fi header row to system tray network detailed view (Closed)
Patch Set: [ash-md] Materializes system tray network detailed view (rebased) Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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_md.h"
6
7 #include <stddef.h>
8
9 #include "base/memory/ptr_util.h"
10 #include "chromeos/dbus/dbus_thread_manager.h"
11 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
12 #include "chromeos/dbus/power_manager_client.h"
13 #include "chromeos/login/login_state.h"
14 #include "chromeos/network/managed_network_configuration_handler.h"
15 #include "chromeos/network/network_state.h"
16 #include "chromeos/network/network_state_handler.h"
17 #include "chromeos/network/network_state_handler_observer.h"
18 #include "components/device_event_log/device_event_log.h"
19 #include "grit/ui_chromeos_strings.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/chromeos/network/network_icon.h"
23 #include "ui/chromeos/network/network_icon_animation.h"
24 #include "ui/chromeos/network/network_info.h"
25 #include "ui/chromeos/network/network_list_delegate.h"
26 #include "ui/gfx/font.h"
27 #include "ui/gfx/paint_vector_icon.h"
28 #include "ui/gfx/vector_icons_public.h"
29 #include "ui/views/border.h"
30 #include "ui/views/controls/button/image_button.h"
31 #include "ui/views/controls/button/toggle_button.h"
32 #include "ui/views/controls/label.h"
33 #include "ui/views/layout/box_layout.h"
34 #include "ui/views/view.h"
35
36 using chromeos::LoginState;
37 using chromeos::NetworkHandler;
38 using chromeos::NetworkStateHandler;
39 using chromeos::ManagedNetworkConfigurationHandler;
40 using chromeos::NetworkTypePattern;
41
42 namespace ui {
43
44 namespace {
45
46 const int kWifiRowHeight = 48;
47 const int kWifiIconSize = 10;
48 const int kWifiRowVerticalInset = 4;
49 const int kWifiRowLeftInset = 18;
50 const int kWifiRowRightInset = 10;
51 const int kWifiRowSeparatorThickness = 1;
52 const int kWifiRowVerticalSpacing = 8;
53 const int kWifiRowChildSpacing = 28;
54 const SkColor kWifiRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
55
56 bool IsProhibitedByPolicy(const chromeos::NetworkState* network) {
57 if (!NetworkTypePattern::WiFi().MatchesType(network->type()))
58 return false;
59 if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn())
60 return false;
61 ManagedNetworkConfigurationHandler* managed_configuration_handler =
62 NetworkHandler::Get()->managed_network_configuration_handler();
63 const base::DictionaryValue* global_network_config =
64 managed_configuration_handler->GetGlobalConfigFromPolicy(
65 std::string() /* no username hash, device policy */);
66 bool policy_prohibites_unmanaged = false;
67 if (global_network_config) {
68 global_network_config->GetBooleanWithoutPathExpansion(
69 ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
70 &policy_prohibites_unmanaged);
71 }
72 if (!policy_prohibites_unmanaged)
73 return false;
74 return !managed_configuration_handler->FindPolicyByGuidAndProfile(
75 network->guid(), network->profile_path());
76 }
77
78 } // namespace
79
80 class NetworkListViewMd::WifiHeaderRowView : public views::View {
81 public:
82 WifiHeaderRowView(views::ButtonListener* listener, bool enabled)
83 : views::View(),
84 listener_(listener),
85 label_(nullptr),
86 toggle_(nullptr),
87 join_(nullptr) {
88 Init();
89 SetWifiEnabled(enabled);
90 }
91
92 ~WifiHeaderRowView() override {}
93
94 void SetWifiEnabled(bool enabled) {
95 join_->SetVisible(enabled);
96 toggle_->SetIsOn(enabled, true);
97 }
98
99 const views::Button* toggle() const { return toggle_; }
100 const views::Button* join() const { return join_; }
101 bool is_toggled() const { return toggle_->is_on(); }
102
103 protected:
104 // views::View:
105 gfx::Size GetPreferredSize() const override {
106 gfx::Size size = views::View::GetPreferredSize();
107 size.set_height(kWifiRowHeight);
108 return size;
109 }
110
111 int GetHeightForWidth(int width) const override { return kWifiRowHeight; }
112
113 private:
114 void Init() {
115 // TODO(tdanderson): Need to unify this with the generic menu row class.
116 SetBorder(views::Border::CreateSolidSidedBorder(
117 kWifiRowSeparatorThickness, 0, 0, 0, kWifiRowSeparatorColor));
118 views::View* container = new views::View;
119 container->SetBorder(views::Border::CreateEmptyBorder(
120 kWifiRowVerticalInset, kWifiRowLeftInset, kWifiRowVerticalInset,
121 kWifiRowRightInset));
122 views::BoxLayout* layout =
123 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
124 layout->set_cross_axis_alignment(
125 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
126 SetLayoutManager(layout);
127 AddChildView(container);
128 layout->SetFlexForView(container, 1);
129
130 views::BoxLayout* container_layout =
131 new views::BoxLayout(views::BoxLayout::kHorizontal, 0,
132 kWifiRowVerticalSpacing, kWifiRowChildSpacing);
133 container->SetLayoutManager(container_layout);
134 SkColor color = GetNativeTheme()->GetSystemColor(
135 ui::NativeTheme::kColorId_CallToActionColor);
136 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
137 label_ = new views::Label(
138 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_WIFI),
139 rb.GetFontList(ui::ResourceBundle::BoldFont));
140 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
141 label_->SetEnabledColor(color);
142 container->AddChildView(label_);
143 container_layout->SetFlexForView(label_, 1);
144
145 join_ = new views::ImageButton(listener_);
146 join_image_ = network_icon::GetImageForNewWifiNetwork(
147 SkColorSetA(color, 0xFF / 2), color);
148 join_->SetImage(views::CustomButton::STATE_NORMAL, &join_image_);
149 join_->SetImage(views::CustomButton::STATE_HOVERED, &join_image_);
150 join_->SetImage(views::CustomButton::STATE_PRESSED, &join_image_);
151 join_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
152 views::ImageButton::ALIGN_MIDDLE);
153 join_->SetMinimumImageSize(gfx::Size(kWifiIconSize, kWifiIconSize));
154 container->AddChildView(join_);
155
156 toggle_ = new views::ToggleButton(listener_);
157 container->AddChildView(toggle_);
158 }
159
160 views::ButtonListener* listener_;
161 views::Label* label_;
162 views::ToggleButton* toggle_;
163 views::ImageButton* join_;
Evan Stade 2016/09/23 21:32:12 comments please?
varkha 2016/09/29 20:31:01 Done.
164 gfx::ImageSkia join_image_;
165
166 DISALLOW_COPY_AND_ASSIGN(WifiHeaderRowView);
167 };
168
169 // NetworkListViewMd:
170
171 NetworkListViewMd::NetworkListViewMd(NetworkListDelegate* delegate)
172 : needs_relayout_(false),
173 delegate_(delegate),
174 no_wifi_networks_view_(nullptr),
175 no_cellular_networks_view_(nullptr),
176 wifi_header_view_(nullptr) {
177 CHECK(delegate_);
178 }
179
180 NetworkListViewMd::~NetworkListViewMd() {
181 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
182 }
183
184 void NetworkListViewMd::Update() {
185 CHECK(container_);
186 NetworkStateHandler::NetworkStateList network_list;
187 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
188 handler->GetVisibleNetworkList(&network_list);
189 UpdateNetworks(network_list);
190 OrderNetworks();
191 UpdateNetworkIcons();
192 UpdateNetworkListInternal();
193 }
194
195 bool NetworkListViewMd::IsNetworkEntry(views::View* view,
196 std::string* service_path) const {
197 std::map<views::View*, std::string>::const_iterator found =
198 network_map_.find(view);
199 if (found == network_map_.end())
200 return false;
201 *service_path = found->second;
202 return true;
203 }
204
205 void NetworkListViewMd::UpdateNetworks(
206 const NetworkStateHandler::NetworkStateList& networks) {
207 SCOPED_NET_LOG_IF_SLOW();
208 network_list_.clear();
209 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
210 for (NetworkStateHandler::NetworkStateList::const_iterator iter =
211 networks.begin();
212 iter != networks.end(); ++iter) {
213 const chromeos::NetworkState* network = *iter;
214 if (!pattern.MatchesType(network->type()))
215 continue;
216 network_list_.push_back(base::MakeUnique<NetworkInfo>(network->path()));
217 }
218 }
219
220 void NetworkListViewMd::OrderNetworks() {
221 struct CompareNetwork {
222 explicit CompareNetwork(NetworkStateHandler* handler) : handler_(handler) {}
223
224 // Returns true if |network1| is less than (i.e. is ordered before)
225 // |network2|.
226 bool operator()(const std::unique_ptr<NetworkInfo>& network1,
227 const std::unique_ptr<NetworkInfo>& network2) {
228 int order1 = GetOrder(handler_->GetNetworkState(network1->service_path));
229 int order2 = GetOrder(handler_->GetNetworkState(network2->service_path));
230 const bool above =
Evan Stade 2016/09/23 21:32:12 nit, I think I've usually seen this written as: i
varkha 2016/09/29 20:31:01 Done.
231 (order1 < order2) ||
232 (order1 == order2 && network1->highlight && !network2->highlight) ||
233 (order1 == order2 &&
234 network1->service_path.compare(network2->service_path) < 0);
235 return above;
236 }
237
238 private:
239 static int GetOrder(const chromeos::NetworkState* network) {
240 if (!network)
241 return 999;
242 if (network->Matches(NetworkTypePattern::Ethernet()))
243 return 0;
244 if (network->Matches(NetworkTypePattern::Cellular()))
245 return 1;
246 if (network->Matches(NetworkTypePattern::Mobile()))
247 return 2;
248 if (network->Matches(NetworkTypePattern::WiFi()))
249 return 3;
250 return 4;
251 }
252
253 NetworkStateHandler* handler_;
254 };
255 std::sort(network_list_.begin(), network_list_.end(),
256 CompareNetwork(NetworkHandler::Get()->network_state_handler()));
257 }
258
259 void NetworkListViewMd::UpdateNetworkIcons() {
260 SCOPED_NET_LOG_IF_SLOW();
261 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
262
263 // First, update state for all networks.
264 bool animating = false;
265
266 for (auto& info : network_list_) {
267 const chromeos::NetworkState* network =
268 handler->GetNetworkState(info->service_path);
269 if (!network)
270 continue;
271 bool prohibited_by_policy = IsProhibitedByPolicy(network);
272 info->label =
273 network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST);
274 info->image =
275 network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST);
276 info->disable =
277 (network->activation_state() == shill::kActivationStateActivating) ||
278 prohibited_by_policy;
279 info->highlight =
280 network->IsConnectedState() || network->IsConnectingState();
281 info->is_wifi = network->Matches(NetworkTypePattern::WiFi());
282 if (prohibited_by_policy) {
283 info->tooltip =
284 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED);
285 }
286 if (!animating && network->IsConnectingState())
287 animating = true;
288 }
289 if (animating)
290 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
291 else
292 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
293 }
294
295 void NetworkListViewMd::UpdateNetworkListInternal() {
296 SCOPED_NET_LOG_IF_SLOW();
297 // Get the updated list entries.
298 needs_relayout_ = false;
Evan Stade 2016/09/23 21:32:12 is this necessary?
varkha 2016/09/29 20:31:01 I thought so. This update is called from time to t
299 network_map_.clear();
300 std::set<std::string> new_service_paths;
301 UpdateNetworkListEntries(&new_service_paths);
302
303 // Remove old children.
304 std::set<std::string> remove_service_paths;
305 for (ServicePathMap::const_iterator it = service_path_map_.begin();
Evan Stade 2016/09/23 21:32:12 auto?
varkha 2016/09/29 20:31:01 Done.
306 it != service_path_map_.end(); ++it) {
307 if (new_service_paths.find(it->first) == new_service_paths.end()) {
308 remove_service_paths.insert(it->first);
309 network_map_.erase(it->second);
310 delete it->second;
311 needs_relayout_ = true;
312 }
313 }
314
315 for (std::set<std::string>::const_iterator remove_it =
Evan Stade 2016/09/23 21:32:12 auto?
varkha 2016/09/29 20:31:01 Done.
316 remove_service_paths.begin();
317 remove_it != remove_service_paths.end(); ++remove_it) {
318 service_path_map_.erase(*remove_it);
319 }
320
321 if (!needs_relayout_)
322 return;
323
324 views::View* selected_view = nullptr;
325 for (const auto& iter : service_path_map_) {
326 if (delegate_->IsViewHovered(iter.second)) {
327 selected_view = iter.second;
328 break;
329 }
330 }
331 container_->SizeToPreferredSize();
332 delegate_->RelayoutScrollList();
333 if (selected_view)
334 container_->ScrollRectToVisible(selected_view->bounds());
335 }
336
337 void NetworkListViewMd::UpdateNetworkListEntries(
338 std::set<std::string>* new_service_paths) {
Evan Stade 2016/09/23 21:32:12 this one definitely seems like it should be a retu
varkha 2016/09/29 20:31:01 Sure. How about this?
339 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
340
341 // Keep an index of the last inserted child.
342 int index = 0;
343
344 // High-priority networks (not Wi-Fi).
345 UpdateNetworkChildren(false /* not Wi-Fi */, new_service_paths, &index);
Evan Stade 2016/09/23 21:32:12 maybe std::set<string> new_service_paths = Update
varkha 2016/09/29 20:31:01 Done.
346
347 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
348 if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) {
349 // Cellular initializing.
350 int message_id = network_icon::GetCellularUninitializedMsg();
351 if (!message_id &&
352 handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
353 !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
354 message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS;
355 }
356 UpdateInfoLabel(message_id, &index, &no_cellular_networks_view_);
Evan Stade 2016/09/23 21:32:12 I'd consider making this: UpdateInfoLabel(message
varkha 2016/09/29 20:31:01 Done.
357 }
358
359 if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) {
360 UpdateWifiHeaderRow(
361 handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), &index,
362 &wifi_header_view_);
363
364 // "Wifi Enabled / Disabled".
365 int message_id = 0;
366 if (network_list_.empty()) {
367 message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
368 ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
369 : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
370 }
371 UpdateInfoLabel(message_id, &index, &no_wifi_networks_view_);
372
373 // Wi-Fi networks.
374 UpdateNetworkChildren(true /* Wi-Fi */, new_service_paths, &index);
Evan Stade 2016/09/23 21:32:13 and here: std::set<string> new_wifi_service_paths
varkha 2016/09/29 20:31:01 Done.
375 }
376
377 // No networks or other messages (fallback).
378 if (index == 0) {
379 UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, &index,
380 &no_wifi_networks_view_);
381 }
Evan Stade 2016/09/23 21:32:12 I think if you make all these param changes then a
varkha 2016/09/29 20:31:01 Done.
382 }
383
384 void NetworkListViewMd::UpdateNetworkChildren(
385 bool is_wifi,
386 std::set<std::string>* new_service_paths,
387 int* child_index) {
388 CHECK(new_service_paths);
389 CHECK(child_index);
390 int index = *child_index;
391 for (const auto& info : network_list_) {
392 if (info->is_wifi != is_wifi)
393 continue;
394 UpdateNetworkChild(index++, info.get());
395 new_service_paths->insert(info->service_path);
396 }
397 *child_index = index;
398 }
399
400 void NetworkListViewMd::UpdateNetworkChild(int index, const NetworkInfo* info) {
401 views::View* network_view = nullptr;
402 ServicePathMap::const_iterator found =
403 service_path_map_.find(info->service_path);
404 if (found == service_path_map_.end()) {
405 network_view = delegate_->CreateViewForNetwork(*info);
406 container_->AddChildViewAt(network_view, index);
407 needs_relayout_ = true;
408 } else {
409 network_view = found->second;
410 network_view->RemoveAllChildViews(true);
411 delegate_->UpdateViewForNetwork(network_view, *info);
412 network_view->Layout();
413 network_view->SchedulePaint();
414 if (PlaceViewAtIndex(network_view, index))
415 needs_relayout_ = true;
416 }
417 if (info->disable)
418 network_view->SetEnabled(false);
419 network_map_[network_view] = info->service_path;
420 service_path_map_[info->service_path] = network_view;
421 }
422
423 bool NetworkListViewMd::PlaceViewAtIndex(views::View* view, int index) {
424 if (container_->child_at(index) == view)
425 return false;
426 container_->ReorderChildView(view, index);
427 return true;
428 }
429
430 void NetworkListViewMd::UpdateInfoLabel(int message_id,
Evan Stade 2016/09/23 21:32:13 I wrote this out to see if it seemed any clearer.
varkha 2016/09/29 20:31:01 PTAL. I realize that it's OK to delete nullptr but
431 int* child_index,
432 views::Label** label) {
433 CHECK(child_index);
434 CHECK(label);
435 if (message_id) {
436 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
437 base::string16 text = rb.GetLocalizedString(message_id);
438 if (!*label) {
439 *label = delegate_->CreateInfoLabel();
440 (*label)->SetText(text);
441 container_->AddChildViewAt(*label, *child_index);
442 needs_relayout_ = true;
443 } else {
444 (*label)->SetText(text);
445 if (PlaceViewAtIndex(*label, *child_index))
446 needs_relayout_ = true;
447 }
448 ++(*child_index);
449 } else if (*label) {
450 delete *label;
451 *label = nullptr;
452 needs_relayout_ = true;
453 }
454 }
455
456 void NetworkListViewMd::UpdateWifiHeaderRow(bool enabled,
457 int* child_index,
Evan Stade 2016/09/23 21:32:12 doesn't seem necessary to make this an in/outparam
varkha 2016/09/29 20:31:01 Done.
458 WifiHeaderRowView** view) {
459 CHECK(child_index);
Evan Stade 2016/09/23 21:32:12 I don't think these checks are necessary; it's obv
varkha 2016/09/29 20:31:01 Done.
460 CHECK(view);
461 if (!*view) {
462 *view = new WifiHeaderRowView(this, enabled);
463 container_->AddChildViewAt(*view, *child_index);
464 needs_relayout_ = true;
465 } else {
466 (*view)->SetWifiEnabled(enabled);
467 if (PlaceViewAtIndex(*view, *child_index))
468 needs_relayout_ = true;
469 }
470 ++(*child_index);
471 }
472
473 void NetworkListViewMd::NetworkIconChanged() {
474 Update();
475 }
476
477 void NetworkListViewMd::ButtonPressed(views::Button* sender,
478 const ui::Event& event) {
479 if (sender == wifi_header_view_->toggle()) {
480 NetworkStateHandler* handler =
481 NetworkHandler::Get()->network_state_handler();
482 handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(),
483 wifi_header_view_->is_toggled(),
484 chromeos::network_handler::ErrorCallback());
485 return;
486 } else if (sender == wifi_header_view_->join()) {
Evan Stade 2016/09/23 21:32:12 no else after return I'd do: if (...) { ...
varkha 2016/09/29 20:31:01 Done.
487 delegate_->OnOtherWifiClicked();
488 return;
489 }
490 NOTREACHED();
491 }
492
493 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698