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

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/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;
Evan Stade 2016/09/29 21:07:58 orthogonal to this CL, can you confirm with sgabri
varkha 2016/09/29 23:31:52 The spec says 1dp. I think this separator would lo
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));
Evan Stade 2016/09/29 21:07:58 spec seems to say medium, not bold ?
varkha 2016/09/29 23:31:52 Done.
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_);
Evan Stade 2016/09/29 21:07:58 you only need to set normal, the other states will
varkha 2016/09/29 23:31:52 Done.
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);
Evan Stade 2016/09/29 21:07:58 pretty sure this shouldn't be necessary with the c
varkha 2016/09/29 23:31:52 Done.
153 join_->SetMinimumImageSize(gfx::Size(kWifiIconSize, kWifiIconSize));
Evan Stade 2016/09/29 21:07:58 why is this necessary
varkha 2016/09/29 23:31:52 I think the current code didn't need it anymore.
154 container->AddChildView(join_);
155
156 toggle_ = new views::ToggleButton(listener_);
157 container->AddChildView(toggle_);
158 }
159
160 // ButtonListener to notify when |toggle_| or |join_| are clicked.
161 views::ButtonListener* listener_;
162
163 // Text label for the row.
164 views::Label* label_;
165
166 // ToggleButton to toggle Wi-Fi on or off.
167 views::ToggleButton* toggle_;
168
169 // A button to invoke "Join Wi-Fi network" dialog.
170 views::ImageButton* join_;
171
172 // Image used for the |join_| button.
173 gfx::ImageSkia join_image_;
174
175 DISALLOW_COPY_AND_ASSIGN(WifiHeaderRowView);
176 };
177
178 // NetworkListViewMd:
179
180 NetworkListViewMd::NetworkListViewMd(NetworkListDelegate* delegate)
181 : needs_relayout_(false),
182 delegate_(delegate),
183 no_wifi_networks_view_(nullptr),
184 no_cellular_networks_view_(nullptr),
185 wifi_header_view_(nullptr) {
186 CHECK(delegate_);
187 }
188
189 NetworkListViewMd::~NetworkListViewMd() {
190 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
191 }
192
193 void NetworkListViewMd::Update() {
194 CHECK(container());
195 NetworkStateHandler::NetworkStateList network_list;
196 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
197 handler->GetVisibleNetworkList(&network_list);
198 UpdateNetworks(network_list);
199 OrderNetworks();
200 UpdateNetworkIcons();
201 UpdateNetworkListInternal();
202 }
203
204 bool NetworkListViewMd::IsNetworkEntry(views::View* view,
205 std::string* service_path) const {
206 std::map<views::View*, std::string>::const_iterator found =
207 network_map_.find(view);
208 if (found == network_map_.end())
209 return false;
210 *service_path = found->second;
211 return true;
212 }
213
214 void NetworkListViewMd::UpdateNetworks(
215 const NetworkStateHandler::NetworkStateList& networks) {
216 SCOPED_NET_LOG_IF_SLOW();
217 network_list_.clear();
218 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
219 for (const auto& network : networks) {
220 if (!pattern.MatchesType(network->type()))
Evan Stade 2016/09/29 21:07:58 nit: if (pattern.Matches...) network_list.p
varkha 2016/09/29 23:31:52 Done.
221 continue;
222 network_list_.push_back(base::MakeUnique<NetworkInfo>(network->path()));
223 }
224 }
225
226 void NetworkListViewMd::OrderNetworks() {
227 struct CompareNetwork {
228 explicit CompareNetwork(NetworkStateHandler* handler) : handler_(handler) {}
229
230 // Returns true if |network1| is less than (i.e. is ordered before)
231 // |network2|.
232 bool operator()(const std::unique_ptr<NetworkInfo>& network1,
233 const std::unique_ptr<NetworkInfo>& network2) {
234 int order1 = GetOrder(handler_->GetNetworkState(network1->service_path));
Evan Stade 2016/09/29 21:07:58 nit: imo these temps are no longer necessary
varkha 2016/09/29 23:31:52 Isn't it better to eval those once though? The imp
Evan Stade 2016/10/03 19:28:39 ah somehow i missed that they were used twice each
varkha 2016/10/03 21:27:02 Acknowledged.
235 int order2 = GetOrder(handler_->GetNetworkState(network2->service_path));
236 if (order1 != order2)
237 return order1 < order2;
238 if (network1->highlight != network2->highlight)
239 return network1->highlight;
240 return network1->service_path.compare(network2->service_path) < 0;
241 }
242
243 private:
244 static int GetOrder(const chromeos::NetworkState* network) {
245 if (!network)
246 return 999;
247 if (network->Matches(NetworkTypePattern::Ethernet()))
248 return 0;
249 if (network->Matches(NetworkTypePattern::Cellular()))
250 return 1;
251 if (network->Matches(NetworkTypePattern::Mobile()))
252 return 2;
253 if (network->Matches(NetworkTypePattern::WiFi()))
254 return 3;
255 return 4;
256 }
257
258 NetworkStateHandler* handler_;
259 };
260 std::sort(network_list_.begin(), network_list_.end(),
261 CompareNetwork(NetworkHandler::Get()->network_state_handler()));
262 }
263
264 void NetworkListViewMd::UpdateNetworkIcons() {
265 SCOPED_NET_LOG_IF_SLOW();
266 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
267
268 // First, update state for all networks.
269 bool animating = false;
270
271 for (auto& info : network_list_) {
272 const chromeos::NetworkState* network =
273 handler->GetNetworkState(info->service_path);
274 if (!network)
275 continue;
276 bool prohibited_by_policy = IsProhibitedByPolicy(network);
277 info->label =
278 network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST);
279 info->image =
280 network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST);
281 info->disable =
282 (network->activation_state() == shill::kActivationStateActivating) ||
283 prohibited_by_policy;
284 info->highlight =
285 network->IsConnectedState() || network->IsConnectingState();
286 info->is_wifi = network->Matches(NetworkTypePattern::WiFi());
287 if (prohibited_by_policy) {
288 info->tooltip =
289 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED);
290 }
291 if (!animating && network->IsConnectingState())
292 animating = true;
293 }
294 if (animating)
295 network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
296 else
297 network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
298 }
299
300 void NetworkListViewMd::UpdateNetworkListInternal() {
301 SCOPED_NET_LOG_IF_SLOW();
302 // Get the updated list entries.
303 needs_relayout_ = false;
304 network_map_.clear();
305 std::unique_ptr<std::set<std::string>> new_service_paths =
306 UpdateNetworkListEntries();
307
308 // Remove old children.
309 std::set<std::string> remove_service_paths;
310 for (const auto& iter : service_path_map_) {
311 if (new_service_paths->find(iter.first) == new_service_paths->end()) {
312 remove_service_paths.insert(iter.first);
313 network_map_.erase(iter.second);
314 delete iter.second;
315 needs_relayout_ = true;
316 }
317 }
318
319 for (const auto& remove_iter : remove_service_paths)
320 service_path_map_.erase(remove_iter);
321
322 if (!needs_relayout_)
323 return;
324
325 views::View* selected_view = nullptr;
326 for (const auto& iter : service_path_map_) {
327 if (delegate_->IsViewHovered(iter.second)) {
328 selected_view = iter.second;
329 break;
330 }
331 }
332 container()->SizeToPreferredSize();
333 delegate_->RelayoutScrollList();
334 if (selected_view)
335 container()->ScrollRectToVisible(selected_view->bounds());
336 }
337
338 std::unique_ptr<std::set<std::string>>
339 NetworkListViewMd::UpdateNetworkListEntries() {
340 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
341
342 // First add high-priority networks (not Wi-Fi).
343 std::unique_ptr<std::set<std::string>> new_service_paths =
344 UpdateNetworkChildren(false /* not Wi-Fi */, 0);
345
346 // Keep an index of the last inserted child.
347 int index = new_service_paths->size();
348
349 const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
350 if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) {
351 // Cellular initializing.
352 int message_id = network_icon::GetCellularUninitializedMsg();
353 if (!message_id &&
354 handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
355 !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
356 message_id = IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS;
357 }
358 UpdateInfoLabel(message_id, index, &no_cellular_networks_view_);
359 if (message_id)
360 ++index;
361 }
362
363 if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) {
364 UpdateWifiHeaderRow(
365 handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index,
366 &wifi_header_view_);
367 ++index;
368
369 // "Wifi Enabled / Disabled".
370 int message_id = 0;
371 if (network_list_.empty()) {
372 message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
373 ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
374 : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
375 }
376 UpdateInfoLabel(message_id, index, &no_wifi_networks_view_);
377 if (message_id)
378 ++index;
379
380 // Add Wi-Fi networks.
381 std::unique_ptr<std::set<std::string>> new_wifi_service_paths =
382 UpdateNetworkChildren(true /* Wi-Fi */, index);
383 index += new_wifi_service_paths->size();
384 new_service_paths->insert(new_wifi_service_paths->begin(),
385 new_wifi_service_paths->end());
386 }
387
388 // No networks or other messages (fallback).
389 if (index == 0) {
390 UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index,
391 &no_wifi_networks_view_);
392 }
393
394 return new_service_paths;
395 }
396
397 std::unique_ptr<std::set<std::string>> NetworkListViewMd::UpdateNetworkChildren(
398 bool is_wifi,
399 int index) {
400 std::unique_ptr<std::set<std::string>> new_service_paths(
401 new std::set<std::string>);
402 for (const auto& info : network_list_) {
403 if (info->is_wifi != is_wifi)
404 continue;
405 UpdateNetworkChild(index++, info.get());
406 new_service_paths->insert(info->service_path);
407 }
408 return new_service_paths;
409 }
410
411 void NetworkListViewMd::UpdateNetworkChild(int index, const NetworkInfo* info) {
412 views::View* network_view = nullptr;
413 ServicePathMap::const_iterator found =
414 service_path_map_.find(info->service_path);
415 if (found == service_path_map_.end()) {
416 network_view = delegate_->CreateViewForNetwork(*info);
417 container()->AddChildViewAt(network_view, index);
418 needs_relayout_ = true;
419 } else {
420 network_view = found->second;
421 network_view->RemoveAllChildViews(true);
422 delegate_->UpdateViewForNetwork(network_view, *info);
423 network_view->Layout();
424 network_view->SchedulePaint();
425 if (PlaceViewAtIndex(network_view, index))
Evan Stade 2016/09/29 21:07:59 looks like you always handle the return value the
varkha 2016/09/29 23:31:52 Done. Simpler indeed.
426 needs_relayout_ = true;
427 }
428 if (info->disable)
429 network_view->SetEnabled(false);
430 network_map_[network_view] = info->service_path;
431 service_path_map_[info->service_path] = network_view;
432 }
433
434 bool NetworkListViewMd::PlaceViewAtIndex(views::View* view, int index) {
435 if (container()->child_at(index) == view)
436 return false;
437 container()->ReorderChildView(view, index);
438 return true;
439 }
440
441 void NetworkListViewMd::UpdateInfoLabel(int message_id,
442 int insertion_index,
443 views::Label** label_ptr) {
444 views::Label* label = *label_ptr;
445 if (!message_id) {
446 if (label) {
447 needs_relayout_ = true;
448 delete label;
449 *label_ptr = nullptr;
450 }
451 return;
452 }
453 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
Evan Stade 2016/09/29 21:07:58 nit: inline rb imo
varkha 2016/09/29 23:31:52 Done.
454 base::string16 text = rb.GetLocalizedString(message_id);
455 if (label) {
456 label->SetText(text);
457 if (PlaceViewAtIndex(label, insertion_index))
458 needs_relayout_ = true;
459 return;
460 }
461 label = delegate_->CreateInfoLabel();
462 label->SetText(text);
463 container()->AddChildViewAt(label, insertion_index);
464 needs_relayout_ = true;
465 *label_ptr = label;
466 }
467
468 void NetworkListViewMd::UpdateWifiHeaderRow(bool enabled,
469 int child_index,
470 WifiHeaderRowView** view) {
471 if (!*view) {
472 *view = new WifiHeaderRowView(this, enabled);
473 container()->AddChildViewAt(*view, child_index);
474 needs_relayout_ = true;
475 } else {
476 (*view)->SetWifiEnabled(enabled);
477 if (PlaceViewAtIndex(*view, child_index))
478 needs_relayout_ = true;
479 }
480 }
481
482 void NetworkListViewMd::NetworkIconChanged() {
483 Update();
484 }
485
486 void NetworkListViewMd::ButtonPressed(views::Button* sender,
487 const ui::Event& event) {
488 if (sender == wifi_header_view_->toggle()) {
489 NetworkStateHandler* handler =
490 NetworkHandler::Get()->network_state_handler();
491 handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(),
492 wifi_header_view_->is_toggled(),
493 chromeos::network_handler::ErrorCallback());
494 } else if (sender == wifi_header_view_->join()) {
495 delegate_->OnOtherWifiClicked();
496 } else {
497 NOTREACHED();
498 }
499 }
500
501 } // 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