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

Side by Side Diff: ash/system/chromeos/network/vpn_list_view.cc

Issue 2109293002: mash: Convert system tray network item to wm common types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: tweak string Created 4 years, 5 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 | « ash/system/chromeos/network/vpn_list_view.h ('k') | ash/system/tray/system_tray.cc » ('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 2015 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/vpn_list_view.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "ash/common/system/tray/hover_highlight_view.h"
12 #include "ash/common/system/tray/system_tray_delegate.h"
13 #include "ash/common/system/tray/tray_constants.h"
14 #include "ash/common/system/tray/tray_popup_label_button.h"
15 #include "ash/common/wm_shell.h"
16 #include "ash/system/chromeos/network/vpn_delegate.h"
17 #include "base/bind.h"
18 #include "base/bind_helpers.h"
19 #include "base/logging.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "chromeos/network/network_connection_handler.h"
23 #include "chromeos/network/network_handler.h"
24 #include "chromeos/network/network_state.h"
25 #include "chromeos/network/network_type_pattern.h"
26 #include "grit/ash_strings.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/chromeos/network/network_icon.h"
29 #include "ui/chromeos/network/network_icon_animation.h"
30 #include "ui/chromeos/network/network_icon_animation_observer.h"
31 #include "ui/chromeos/network/network_list_delegate.h"
32 #include "ui/gfx/geometry/rect.h"
33 #include "ui/gfx/image/image_skia.h"
34 #include "ui/gfx/text_constants.h"
35 #include "ui/views/border.h"
36 #include "ui/views/controls/button/button.h"
37 #include "ui/views/controls/label.h"
38 #include "ui/views/controls/separator.h"
39 #include "ui/views/layout/box_layout.h"
40 #include "ui/views/view.h"
41
42 namespace ash {
43
44 namespace {
45
46 bool IsConnectedOrConnecting(const chromeos::NetworkState* network) {
47 return network->IsConnectedState() || network->IsConnectingState();
48 }
49
50 void IgnoreDisconnectError(const std::string& error_name,
51 std::unique_ptr<base::DictionaryValue> error_data) {}
52
53 // The base class of all list entries, a |HoverHighlightView| with no border.
54 class VPNListEntryBase : public HoverHighlightView {
55 public:
56 // When the user clicks the entry, the |parent|'s OnViewClicked() will be
57 // invoked.
58 explicit VPNListEntryBase(VPNListView* parent);
59
60 private:
61 DISALLOW_COPY_AND_ASSIGN(VPNListEntryBase);
62 };
63
64 // A list entry that represents a VPN provider.
65 class VPNListProviderEntry : public VPNListEntryBase {
66 public:
67 VPNListProviderEntry(VPNListView* parent, const std::string& name);
68
69 private:
70 DISALLOW_COPY_AND_ASSIGN(VPNListProviderEntry);
71 };
72
73 // A list entry that represents a network. If the network is currently
74 // connecting, the icon shown by this list entry will be animated. If the
75 // network is currently connected, a disconnect button will be shown next to its
76 // name.
77 class VPNListNetworkEntry : public VPNListEntryBase,
78 public ui::network_icon::AnimationObserver,
79 public views::ButtonListener {
80 public:
81 VPNListNetworkEntry(VPNListView* parent,
82 const chromeos::NetworkState* network);
83 ~VPNListNetworkEntry() override;
84
85 // ui::network_icon::AnimationObserver:
86 void NetworkIconChanged() override;
87
88 // views::ButtonListener:
89 void ButtonPressed(views::Button* sender, const ui::Event& event) override;
90
91 private:
92 // A disconnect button that will be shown if the network is currently
93 // connected. Updates the list entry's hover state as the mouse enters/exits
94 // the button.
95 class DisconnectButton : public TrayPopupLabelButton {
96 public:
97 explicit DisconnectButton(VPNListNetworkEntry* parent);
98
99 private:
100 // TrayPopupLabelButton:
101 void OnMouseEntered(const ui::MouseEvent& event) override;
102 void OnMouseExited(const ui::MouseEvent& event) override;
103 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
104
105 VPNListNetworkEntry* parent_;
106
107 DISALLOW_COPY_AND_ASSIGN(DisconnectButton);
108 };
109
110 void UpdateFromNetworkState(const chromeos::NetworkState* network);
111
112 const std::string service_path_;
113
114 DisconnectButton* disconnect_button_ = nullptr;
115
116 DISALLOW_COPY_AND_ASSIGN(VPNListNetworkEntry);
117 };
118
119 VPNListEntryBase::VPNListEntryBase(VPNListView* parent)
120 : HoverHighlightView(parent) {
121 SetBorder(
122 views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0));
123 }
124
125 VPNListProviderEntry::VPNListProviderEntry(VPNListView* parent,
126 const std::string& name)
127 : VPNListEntryBase(parent) {
128 views::Label* const label =
129 AddLabel(base::UTF8ToUTF16(name), gfx::ALIGN_LEFT, false /* highlight */);
130 label->SetBorder(views::Border::CreateEmptyBorder(5, 0, 5, 0));
131 }
132
133 VPNListNetworkEntry::VPNListNetworkEntry(VPNListView* parent,
134 const chromeos::NetworkState* network)
135 : VPNListEntryBase(parent), service_path_(network->path()) {
136 UpdateFromNetworkState(network);
137 }
138
139 VPNListNetworkEntry::~VPNListNetworkEntry() {
140 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
141 }
142
143 void VPNListNetworkEntry::NetworkIconChanged() {
144 UpdateFromNetworkState(
145 chromeos::NetworkHandler::Get()->network_state_handler()->GetNetworkState(
146 service_path_));
147 }
148
149 void VPNListNetworkEntry::ButtonPressed(views::Button* sender,
150 const ui::Event& event) {
151 WmShell::Get()->RecordUserMetricsAction(
152 UMA_STATUS_AREA_VPN_DISCONNECT_CLICKED);
153 chromeos::NetworkHandler::Get()
154 ->network_connection_handler()
155 ->DisconnectNetwork(service_path_, base::Bind(&base::DoNothing),
156 base::Bind(&IgnoreDisconnectError));
157 }
158
159 VPNListNetworkEntry::DisconnectButton::DisconnectButton(
160 VPNListNetworkEntry* parent)
161 : TrayPopupLabelButton(
162 parent,
163 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)),
164 parent_(parent) {
165 DCHECK(parent_);
166 }
167
168 void VPNListNetworkEntry::DisconnectButton::OnMouseEntered(
169 const ui::MouseEvent& event) {
170 TrayPopupLabelButton::OnMouseEntered(event);
171 parent_->SetHoverHighlight(false);
172 }
173
174 void VPNListNetworkEntry::DisconnectButton::OnMouseExited(
175 const ui::MouseEvent& event) {
176 TrayPopupLabelButton::OnMouseExited(event);
177 if (parent_->IsMouseHovered())
178 parent_->SetHoverHighlight(true);
179 }
180
181 void VPNListNetworkEntry::DisconnectButton::OnBoundsChanged(
182 const gfx::Rect& previous_bounds) {
183 TrayPopupLabelButton::OnBoundsChanged(previous_bounds);
184 if (IsMouseHovered()) {
185 SetState(STATE_HOVERED);
186 parent_->SetHoverHighlight(false);
187 }
188 }
189
190 void VPNListNetworkEntry::UpdateFromNetworkState(
191 const chromeos::NetworkState* network) {
192 if (network && network->IsConnectingState())
193 ui::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
194 else
195 ui::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
196
197 if (!network) {
198 // This is a transient state where the network has been removed already but
199 // the network list in the UI has not been updated yet.
200 return;
201 }
202
203 RemoveAllChildViews(true);
204 disconnect_button_ = nullptr;
205
206 AddIconAndLabel(ui::network_icon::GetImageForNetwork(
207 network, ui::network_icon::ICON_TYPE_LIST),
208 ui::network_icon::GetLabelForNetwork(
209 network, ui::network_icon::ICON_TYPE_LIST),
210 IsConnectedOrConnecting(network));
211 if (IsConnectedOrConnecting(network)) {
212 disconnect_button_ = new DisconnectButton(this);
213 AddChildView(disconnect_button_);
214 SetBorder(
215 views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 3));
216 } else {
217 SetBorder(
218 views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0));
219 }
220
221 // The icon and the disconnect button are always set to their preferred size.
222 // All remaining space is used for the network name.
223 views::BoxLayout* layout = new views::BoxLayout(
224 views::BoxLayout::kHorizontal, 0, 3, kTrayPopupPaddingBetweenItems);
225 SetLayoutManager(layout);
226 layout->SetDefaultFlex(0);
227 layout->SetFlexForView(text_label(), 1);
228 Layout();
229 }
230
231 } // namespace
232
233 VPNListView::VPNListView(ui::NetworkListDelegate* delegate)
234 : delegate_(delegate) {
235 WmShell::Get()->system_tray_delegate()->GetVPNDelegate()->AddObserver(this);
236 }
237
238 VPNListView::~VPNListView() {
239 // We need the check as on shell destruction, the delegate is destroyed first.
240 SystemTrayDelegate* const system_tray_delegate =
241 WmShell::Get()->system_tray_delegate();
242 if (system_tray_delegate) {
243 VPNDelegate* const vpn_delegate = system_tray_delegate->GetVPNDelegate();
244 if (vpn_delegate)
245 vpn_delegate->RemoveObserver(this);
246 }
247 }
248
249 void VPNListView::Update() {
250 // Before updating the list, determine whether the user was hovering over one
251 // of the VPN provider or network entries.
252 std::unique_ptr<VPNProvider::Key> hovered_provider_key;
253 std::string hovered_network_service_path;
254 for (const std::pair<const views::View* const, VPNProvider::Key>& provider :
255 provider_view_key_map_) {
256 if (static_cast<const HoverHighlightView*>(provider.first)->hover()) {
257 hovered_provider_key.reset(new VPNProvider::Key(provider.second));
258 break;
259 }
260 }
261 if (!hovered_provider_key) {
262 for (const std::pair<const views::View*, std::string>& entry :
263 network_view_service_path_map_) {
264 if (static_cast<const HoverHighlightView*>(entry.first)->hover()) {
265 hovered_network_service_path = entry.second;
266 break;
267 }
268 }
269 }
270
271 // Clear the list.
272 container_->RemoveAllChildViews(true);
273 provider_view_key_map_.clear();
274 network_view_service_path_map_.clear();
275 list_empty_ = true;
276 container_->SetLayoutManager(
277 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
278
279 // Get the list of available VPN networks, in shill's priority order.
280 chromeos::NetworkStateHandler::NetworkStateList networks;
281 chromeos::NetworkHandler::Get()
282 ->network_state_handler()
283 ->GetVisibleNetworkListByType(chromeos::NetworkTypePattern::VPN(),
284 &networks);
285
286 if (!networks.empty() && IsConnectedOrConnecting(networks.front())) {
287 // If there is a connected or connecting network, show that network first.
288 AddNetwork(networks.front());
289 networks.erase(networks.begin());
290 }
291
292 // Show all VPN providers and all networks that are currently disconnected.
293 AddProvidersAndNetworks(networks);
294
295 // Determine whether one of the new list entries corresponds to the entry that
296 // the user was previously hovering over. If such an entry is found, the list
297 // will be scrolled to ensure the entry is visible.
298 const views::View* scroll_to_show_view = nullptr;
299 if (hovered_provider_key) {
300 for (const std::pair<const views::View* const, VPNProvider::Key>& provider :
301 provider_view_key_map_) {
302 if (provider.second == *hovered_provider_key) {
303 scroll_to_show_view = provider.first;
304 break;
305 }
306 }
307 } else if (!hovered_network_service_path.empty()) {
308 for (const std::pair<const views::View*, std::string>& entry :
309 network_view_service_path_map_) {
310 if (entry.second == hovered_network_service_path) {
311 scroll_to_show_view = entry.first;
312 break;
313 }
314 }
315 }
316
317 // Layout the updated list.
318 container_->SizeToPreferredSize();
319 delegate_->RelayoutScrollList();
320
321 if (scroll_to_show_view) {
322 // Scroll the list so that |scroll_to_show_view| is in view.
323 container_->ScrollRectToVisible(scroll_to_show_view->bounds());
324 }
325 }
326
327 bool VPNListView::IsNetworkEntry(views::View* view,
328 std::string* service_path) const {
329 const auto& entry = network_view_service_path_map_.find(view);
330 if (entry == network_view_service_path_map_.end())
331 return false;
332 *service_path = entry->second;
333 return true;
334 }
335
336 void VPNListView::OnVPNProvidersChanged() {
337 Update();
338 }
339
340 void VPNListView::OnViewClicked(views::View* sender) {
341 const auto& provider = provider_view_key_map_.find(sender);
342 if (provider != provider_view_key_map_.end()) {
343 // If the user clicks on a provider entry, request that the "add network"
344 // dialog for this provider be shown.
345 const VPNProvider::Key& key = provider->second;
346 WmShell::Get()->RecordUserMetricsAction(
347 key.third_party ? UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED
348 : UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED);
349 WmShell::Get()->system_tray_delegate()->GetVPNDelegate()->ShowAddPage(key);
350 return;
351 }
352
353 // If the user clicked on a network entry, let the |delegate_| trigger a
354 // connection attempt (if the network is currently disconnected) or show a
355 // configuration dialog (if the network is currently connected or connecting).
356 delegate_->OnViewClicked(sender);
357 }
358
359 void VPNListView::AddNetwork(const chromeos::NetworkState* network) {
360 views::View* entry(new VPNListNetworkEntry(this, network));
361 container_->AddChildView(entry);
362 network_view_service_path_map_[entry] = network->path();
363 list_empty_ = false;
364 }
365
366 void VPNListView::AddProviderAndNetworks(
367 const VPNProvider::Key& key,
368 const std::string& name,
369 const chromeos::NetworkStateHandler::NetworkStateList& networks) {
370 // Add a visual separator, unless this is the topmost entry in the list.
371 if (!list_empty_) {
372 views::Separator* const separator =
373 new views::Separator(views::Separator::HORIZONTAL);
374 separator->SetColor(kBorderLightColor);
375 container_->AddChildView(separator);
376 } else {
377 list_empty_ = false;
378 }
379 // Add a list entry for the VPN provider.
380 views::View* provider(new VPNListProviderEntry(this, name));
381 container_->AddChildView(provider);
382 provider_view_key_map_[provider] = key;
383 // Add the networks belonging to this provider, in the priority order returned
384 // by shill.
385 for (const chromeos::NetworkState* const& network : networks) {
386 if (key.MatchesNetwork(*network))
387 AddNetwork(network);
388 }
389 }
390
391 void VPNListView::AddProvidersAndNetworks(
392 const chromeos::NetworkStateHandler::NetworkStateList& networks) {
393 // Get the list of VPN providers enabled in the primary user's profile.
394 std::vector<VPNProvider> providers = WmShell::Get()
395 ->system_tray_delegate()
396 ->GetVPNDelegate()
397 ->GetVPNProviders();
398
399 // Add providers with at least one configured network along with their
400 // networks. Providers are added in the order of their highest priority
401 // network.
402 for (const chromeos::NetworkState* const& network : networks) {
403 for (auto provider = providers.begin(); provider != providers.end();
404 ++provider) {
405 if (!provider->key.MatchesNetwork(*network))
406 continue;
407 AddProviderAndNetworks(provider->key, provider->name, networks);
408 providers.erase(provider);
409 break;
410 }
411 }
412
413 // Add providers without any configured networks, in the order that the
414 // providers were returned by the extensions system.
415 for (const VPNProvider& provider : providers)
416 AddProviderAndNetworks(provider.key, provider.name, networks);
417 }
418
419 } // namespace ash
OLDNEW
« no previous file with comments | « ash/system/chromeos/network/vpn_list_view.h ('k') | ash/system/tray/system_tray.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698