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

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 (comments) 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
« no previous file with comments | « ui/chromeos/network/network_list_md.h ('k') | ui/chromeos/network/network_list_view_base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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/painter.h"
35 #include "ui/views/view.h"
36
37 using chromeos::LoginState;
38 using chromeos::NetworkHandler;
39 using chromeos::NetworkStateHandler;
40 using chromeos::ManagedNetworkConfigurationHandler;
41 using chromeos::NetworkTypePattern;
42
43 namespace ui {
44
45 namespace {
46
47 const int kWiFiButtonSize = 48;
48 const int kWifiRowVerticalInset = 4;
49 const int kWifiRowLeftInset = 18;
50 const int kWifiRowRightInset = 14;
51 const int kWifiRowSeparatorThickness = 1;
52 const int kWifiRowChildSpacing = 14;
53 ;
54 const SkColor kWifiRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
55 const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250);
56
57 bool IsProhibitedByPolicy(const chromeos::NetworkState* network) {
58 if (!NetworkTypePattern::WiFi().MatchesType(network->type()))
59 return false;
60 if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn())
61 return false;
62 ManagedNetworkConfigurationHandler* managed_configuration_handler =
63 NetworkHandler::Get()->managed_network_configuration_handler();
64 const base::DictionaryValue* global_network_config =
65 managed_configuration_handler->GetGlobalConfigFromPolicy(
66 std::string() /* no username hash, device policy */);
67 bool policy_prohibites_unmanaged = false;
68 if (global_network_config) {
69 global_network_config->GetBooleanWithoutPathExpansion(
70 ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
71 &policy_prohibites_unmanaged);
72 }
73 if (!policy_prohibites_unmanaged)
74 return false;
75 return !managed_configuration_handler->FindPolicyByGuidAndProfile(
76 network->guid(), network->profile_path());
77 }
78
79 } // namespace
80
81 class NetworkListViewMd::WifiHeaderRowView : public views::View {
82 public:
83 WifiHeaderRowView(views::ButtonListener* listener, bool enabled)
84 : views::View(),
85 listener_(listener),
86 label_(nullptr),
87 toggle_(nullptr),
88 join_(nullptr) {
89 Init();
90 SetWifiEnabled(enabled);
91 }
92
93 ~WifiHeaderRowView() override {}
94
95 void SetWifiEnabled(bool enabled) {
96 join_->SetVisible(enabled);
97 toggle_->SetIsOn(enabled, true);
98 }
99
100 const views::Button* toggle() const { return toggle_; }
101 const views::Button* join() const { return join_; }
102 bool is_toggled() const { return toggle_->is_on(); }
103
104 protected:
105 // views::View:
106 gfx::Size GetPreferredSize() const override {
107 gfx::Size size = views::View::GetPreferredSize();
108 size.set_height(kWiFiButtonSize + kWifiRowVerticalInset * 2);
109 return size;
110 }
111
112 int GetHeightForWidth(int width) const override {
113 return kWiFiButtonSize + kWifiRowVerticalInset * 2;
114 }
115
116 private:
117 void Init() {
118 // TODO(tdanderson): Need to unify this with the generic menu row class.
119 SetBorder(views::Border::CreateSolidSidedBorder(
120 kWifiRowSeparatorThickness, 0, 0, 0, kWifiRowSeparatorColor));
121 views::View* container = new views::View;
122 container->SetBorder(views::Border::CreateEmptyBorder(
123 0, kWifiRowLeftInset, 0, kWifiRowRightInset));
124 views::BoxLayout* layout =
125 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
126 // layout->set_main_axis_alignment(
127 // views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
Evan Stade 2016/10/03 19:28:39 ?
varkha 2016/10/03 21:27:02 Done.
128 layout->set_cross_axis_alignment(
129 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
130 SetLayoutManager(layout);
131 AddChildView(container);
132 layout->SetFlexForView(container, 1);
133
134 views::BoxLayout* container_layout = new views::BoxLayout(
135 views::BoxLayout::kHorizontal, 0, 0, kWifiRowChildSpacing);
136 container->SetLayoutManager(container_layout);
137 SkColor color = GetNativeTheme()->GetSystemColor(
138 ui::NativeTheme::kColorId_ProminentButtonColor);
139 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
140 label_ = new views::Label(
141 rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_WIFI),
142 rb.GetFontList(ui::ResourceBundle::MediumFont));
143 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
144 label_->SetEnabledColor(color);
145 container->AddChildView(label_);
146 container_layout->SetFlexForView(label_, 1);
147
148 // TODO(varkha): Make this a SystemMenuButton.
149 join_ = new views::ImageButton(listener_);
150 join_image_ = network_icon::GetImageForNewWifiNetwork(
151 SkColorSetA(color, 0xFF / 2), color);
152 join_->SetImage(views::CustomButton::STATE_NORMAL, &join_image_);
153
154 const int horizontal_padding = (kWiFiButtonSize - join_image_.width()) / 2;
155 const int vertical_padding = (kWiFiButtonSize - join_image_.height()) / 2;
156 join_->SetBorder(
157 views::Border::CreateEmptyBorder(vertical_padding, horizontal_padding,
Evan Stade 2016/10/03 19:28:39 optional nit: can be views::Border::CreateEmptyBo
varkha 2016/10/03 21:27:02 Done.
158 vertical_padding, horizontal_padding));
159 join_->SetFocusForPlatform();
160 join_->SetFocusPainter(views::Painter::CreateSolidFocusPainter(
161 kFocusBorderColor, gfx::Insets(1, 1, 1, 1)));
Evan Stade 2016/10/03 19:28:39 gfx::Insets(1)
varkha 2016/10/03 21:27:02 Done.
162 container->AddChildView(join_);
163
164 toggle_ = new views::ToggleButton(listener_);
165 // TODO(varkha): Implement focus painter.
166 toggle_->SetFocusForPlatform();
167 views::View* toggle_container = new views::View;
Evan Stade 2016/10/03 19:28:39 this doesn't seem right. The commented out code ab
varkha 2016/10/03 21:27:02 Yes, needed to specify CROSS_AXIS_ALIGNMENT_CENTER
168 views::BoxLayout* toggle_layout =
169 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
170 toggle_layout->set_main_axis_alignment(
171 views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
172 toggle_layout->set_cross_axis_alignment(
173 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
174 toggle_container->SetLayoutManager(toggle_layout);
175 toggle_container->AddChildView(toggle_);
176 container->AddChildView(toggle_container);
177 }
178
179 // ButtonListener to notify when |toggle_| or |join_| are clicked.
180 views::ButtonListener* listener_;
181
182 // Text label for the row.
183 views::Label* label_;
184
185 // ToggleButton to toggle Wi-Fi on or off.
186 views::ToggleButton* toggle_;
187
188 // A button to invoke "Join Wi-Fi network" dialog.
189 views::ImageButton* join_;
190
191 // Image used for the |join_| button.
192 gfx::ImageSkia join_image_;
193
194 DISALLOW_COPY_AND_ASSIGN(WifiHeaderRowView);
195 };
196
197 // NetworkListViewMd:
198
199 NetworkListViewMd::NetworkListViewMd(NetworkListDelegate* delegate)
200 : needs_relayout_(false),
201 delegate_(delegate),
202 no_wifi_networks_view_(nullptr),
203 no_cellular_networks_view_(nullptr),
204 wifi_header_view_(nullptr) {
205 CHECK(delegate_);
206 }
207
208 NetworkListViewMd::~NetworkListViewMd() {
209 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
210 }
211
212 void NetworkListViewMd::Update() {
213 CHECK(container());
214 NetworkStateHandler::NetworkStateList network_list;
215 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
216 handler->GetVisibleNetworkList(&network_list);
217 UpdateNetworks(network_list);
218 OrderNetworks();
219 UpdateNetworkIcons();
220 UpdateNetworkListInternal();
221 }
222
223 bool NetworkListViewMd::IsNetworkEntry(views::View* view,
224 std::string* service_path) const {
225 std::map<views::View*, std::string>::const_iterator found =
226 network_map_.find(view);
227 if (found == network_map_.end())
228 return false;
229 *service_path = found->second;
230 return true;
231 }
232
233 void NetworkListViewMd::UpdateNetworks(
234 const NetworkStateHandler::NetworkStateList& networks) {
235 SCOPED_NET_LOG_IF_SLOW();
236 network_list_.clear();
237 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
238 for (const auto& network : networks) {
239 if (pattern.MatchesType(network->type()))
240 network_list_.push_back(base::MakeUnique<NetworkInfo>(network->path()));
241 }
242 }
243
244 void NetworkListViewMd::OrderNetworks() {
245 struct CompareNetwork {
246 explicit CompareNetwork(NetworkStateHandler* handler) : handler_(handler) {}
247
248 // Returns true if |network1| is less than (i.e. is ordered before)
249 // |network2|.
250 bool operator()(const std::unique_ptr<NetworkInfo>& network1,
251 const std::unique_ptr<NetworkInfo>& network2) {
252 const int order1 =
253 GetOrder(handler_->GetNetworkState(network1->service_path));
254 const int order2 =
255 GetOrder(handler_->GetNetworkState(network2->service_path));
256 if (order1 != order2)
257 return order1 < order2;
258 if (network1->highlight != network2->highlight)
259 return network1->highlight;
260 return network1->service_path.compare(network2->service_path) < 0;
261 }
262
263 private:
264 static int GetOrder(const chromeos::NetworkState* network) {
265 if (!network)
266 return 999;
267 if (network->Matches(NetworkTypePattern::Ethernet()))
268 return 0;
269 if (network->Matches(NetworkTypePattern::Cellular()))
270 return 1;
271 if (network->Matches(NetworkTypePattern::Mobile()))
272 return 2;
273 if (network->Matches(NetworkTypePattern::WiFi()))
274 return 3;
275 return 4;
276 }
277
278 NetworkStateHandler* handler_;
279 };
280 std::sort(network_list_.begin(), network_list_.end(),
281 CompareNetwork(NetworkHandler::Get()->network_state_handler()));
282 }
283
284 void NetworkListViewMd::UpdateNetworkIcons() {
285 SCOPED_NET_LOG_IF_SLOW();
286 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
287
288 // First, update state for all networks.
289 bool animating = false;
290
291 for (auto& info : network_list_) {
292 const chromeos::NetworkState* network =
293 handler->GetNetworkState(info->service_path);
294 if (!network)
295 continue;
296 bool prohibited_by_policy = IsProhibitedByPolicy(network);
297 info->label =
298 network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST);
299 info->image =
300 network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST);
301 info->disable =
302 (network->activation_state() == shill::kActivationStateActivating) ||
303 prohibited_by_policy;
304 info->highlight =
305 network->IsConnectedState() || network->IsConnectingState();
306 info->is_wifi = network->Matches(NetworkTypePattern::WiFi());
307 if (prohibited_by_policy) {
308 info->tooltip =
309 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED);
310 }
311 if (!animating && network->IsConnectingState())
312 animating = true;
313 }
314 if (animating)
315 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
316 else
317 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
318 }
319
320 void NetworkListViewMd::UpdateNetworkListInternal() {
321 SCOPED_NET_LOG_IF_SLOW();
322 // Get the updated list entries.
323 needs_relayout_ = false;
324 network_map_.clear();
325 std::unique_ptr<std::set<std::string>> new_service_paths =
326 UpdateNetworkListEntries();
327
328 // Remove old children.
329 std::set<std::string> remove_service_paths;
330 for (const auto& iter : service_path_map_) {
331 if (new_service_paths->find(iter.first) == new_service_paths->end()) {
332 remove_service_paths.insert(iter.first);
333 network_map_.erase(iter.second);
334 delete iter.second;
335 needs_relayout_ = true;
336 }
337 }
338
339 for (const auto& remove_iter : remove_service_paths)
340 service_path_map_.erase(remove_iter);
341
342 if (!needs_relayout_)
343 return;
344
345 views::View* selected_view = nullptr;
346 for (const auto& iter : service_path_map_) {
347 if (delegate_->IsViewHovered(iter.second)) {
348 selected_view = iter.second;
349 break;
350 }
351 }
352 container()->SizeToPreferredSize();
353 delegate_->RelayoutScrollList();
354 if (selected_view)
355 container()->ScrollRectToVisible(selected_view->bounds());
356 }
357
358 std::unique_ptr<std::set<std::string>>
359 NetworkListViewMd::UpdateNetworkListEntries() {
360 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
361
362 // First add high-priority networks (not Wi-Fi).
363 std::unique_ptr<std::set<std::string>> new_service_paths =
364 UpdateNetworkChildren(false /* not Wi-Fi */, 0);
365
366 // Keep an index of the last inserted child.
367 int index = new_service_paths->size();
368
369 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
370 if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) {
371 // Cellular initializing.
372 int message_id = network_icon::GetCellularUninitializedMsg();
373 if (!message_id &&
374 handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
375 !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
376 message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS;
377 }
378 UpdateInfoLabel(message_id, index, &no_cellular_networks_view_);
379 if (message_id)
380 ++index;
381 }
382
383 if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) {
384 UpdateWifiHeaderRow(
385 handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index,
386 &wifi_header_view_);
387 ++index;
388
389 // "Wifi Enabled / Disabled".
390 int message_id = 0;
391 if (network_list_.empty()) {
392 message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
393 ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
394 : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
395 }
396 UpdateInfoLabel(message_id, index, &no_wifi_networks_view_);
397 if (message_id)
398 ++index;
399
400 // Add Wi-Fi networks.
401 std::unique_ptr<std::set<std::string>> new_wifi_service_paths =
402 UpdateNetworkChildren(true /* Wi-Fi */, index);
403 index += new_wifi_service_paths->size();
404 new_service_paths->insert(new_wifi_service_paths->begin(),
405 new_wifi_service_paths->end());
406 }
407
408 // No networks or other messages (fallback).
409 if (index == 0) {
410 UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index,
411 &no_wifi_networks_view_);
412 }
413
414 return new_service_paths;
415 }
416
417 std::unique_ptr<std::set<std::string>> NetworkListViewMd::UpdateNetworkChildren(
418 bool is_wifi,
419 int index) {
420 std::unique_ptr<std::set<std::string>> new_service_paths(
421 new std::set<std::string>);
422 for (const auto& info : network_list_) {
423 if (info->is_wifi != is_wifi)
424 continue;
425 UpdateNetworkChild(index++, info.get());
426 new_service_paths->insert(info->service_path);
427 }
428 return new_service_paths;
429 }
430
431 void NetworkListViewMd::UpdateNetworkChild(int index, const NetworkInfo* info) {
432 views::View* network_view = nullptr;
433 ServicePathMap::const_iterator found =
434 service_path_map_.find(info->service_path);
435 if (found == service_path_map_.end()) {
436 network_view = delegate_->CreateViewForNetwork(*info);
437 container()->AddChildViewAt(network_view, index);
438 needs_relayout_ = true;
439 } else {
440 network_view = found->second;
441 network_view->RemoveAllChildViews(true);
442 delegate_->UpdateViewForNetwork(network_view, *info);
443 network_view->Layout();
444 network_view->SchedulePaint();
445 PlaceViewAtIndex(network_view, index);
446 }
447 if (info->disable)
448 network_view->SetEnabled(false);
449 network_map_[network_view] = info->service_path;
450 service_path_map_[info->service_path] = network_view;
451 }
452
453 void NetworkListViewMd::PlaceViewAtIndex(views::View* view, int index) {
454 if (container()->child_at(index) == view)
455 return;
456 container()->ReorderChildView(view, index);
457 needs_relayout_ = true;
458 }
459
460 void NetworkListViewMd::UpdateInfoLabel(int message_id,
461 int insertion_index,
462 views::Label** label_ptr) {
463 views::Label* label = *label_ptr;
464 if (!message_id) {
465 if (label) {
466 needs_relayout_ = true;
467 delete label;
468 *label_ptr = nullptr;
469 }
470 return;
471 }
472 base::string16 text =
473 ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
474 if (label) {
Evan Stade 2016/10/03 19:28:39 if you make PlaceViewAtIndex handle the case where
varkha 2016/10/03 21:27:02 Done.
475 label->SetText(text);
476 PlaceViewAtIndex(label, insertion_index);
477 return;
478 }
479 label = delegate_->CreateInfoLabel();
480 label->SetText(text);
481 container()->AddChildViewAt(label, insertion_index);
482 needs_relayout_ = true;
483 *label_ptr = label;
484 }
485
486 void NetworkListViewMd::UpdateWifiHeaderRow(bool enabled,
487 int child_index,
488 WifiHeaderRowView** view) {
489 if (!*view) {
490 *view = new WifiHeaderRowView(this, enabled);
491 container()->AddChildViewAt(*view, child_index);
492 needs_relayout_ = true;
493 } else {
494 (*view)->SetWifiEnabled(enabled);
495 PlaceViewAtIndex(*view, child_index);
496 }
497 }
498
499 void NetworkListViewMd::NetworkIconChanged() {
500 Update();
501 }
502
503 void NetworkListViewMd::ButtonPressed(views::Button* sender,
504 const ui::Event& event) {
505 if (sender == wifi_header_view_->toggle()) {
506 NetworkStateHandler* handler =
507 NetworkHandler::Get()->network_state_handler();
508 handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(),
509 wifi_header_view_->is_toggled(),
510 chromeos::network_handler::ErrorCallback());
511 } else if (sender == wifi_header_view_->join()) {
512 delegate_->OnOtherWifiClicked();
513 } else {
514 NOTREACHED();
515 }
516 }
517
518 } // namespace ui
OLDNEW
« no previous file with comments | « ui/chromeos/network/network_list_md.h ('k') | ui/chromeos/network/network_list_view_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698