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.
5 #include "athena/system/network_selector.h"
7 #include "base/memory/weak_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chromeos/network/network_configuration_handler.h"
10 #include "chromeos/network/network_connection_handler.h"
11 #include "chromeos/network/network_handler.h"
12 #include "chromeos/network/network_profile_handler.h"
13 #include "chromeos/network/network_state.h"
14 #include "chromeos/network/network_state_handler.h"
15 #include "chromeos/network/network_state_handler_observer.h"
16 #include "chromeos/network/network_type_pattern.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
18 #include "ui/aura/window.h"
19 #include "ui/chromeos/network/network_icon.h"
20 #include "ui/chromeos/network/network_info.h"
21 #include "ui/chromeos/network/network_list.h"
22 #include "ui/chromeos/network/network_list_delegate.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/gfx/canvas.h"
25 #include "ui/gfx/font.h"
26 #include "ui/gfx/font_list.h"
27 #include "ui/gfx/geometry/rect.h"
28 #include "ui/gfx/text_constants.h"
29 #include "ui/views/background.h"
30 #include "ui/views/border.h"
31 #include "ui/views/controls/button/blue_button.h"
32 #include "ui/views/controls/button/button.h"
33 #include "ui/views/controls/image_view.h"
34 #include "ui/views/controls/label.h"
35 #include "ui/views/controls/scroll_view.h"
36 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
37 #include "ui/views/controls/textfield/textfield.h"
38 #include "ui/views/layout/box_layout.h"
39 #include "ui/views/layout/fill_layout.h"
40 #include "ui/views/widget/widget.h"
42 using chromeos::NetworkConfigurationHandler
;
43 using chromeos::NetworkConnectionHandler
;
44 using chromeos::NetworkHandler
;
45 using chromeos::NetworkProfileHandler
;
46 using chromeos::NetworkState
;
50 const int kBackgroundColor
= SkColorSetARGB(0x7f, 0, 0, 0);
52 // The View for the user to enter the password for connceting to a network. This
53 // view also shows an error message if the network connection fails.
54 class PasswordView
: public views::View
, public views::ButtonListener
{
56 PasswordView(const ui::NetworkInfo
& network
,
57 const base::Callback
<void(bool)>& callback
,
58 views::View
* parent_container
)
61 parent_container_(parent_container
),
67 const int kHorizontal
= 5;
68 const int kVertical
= 0;
69 const int kPadding
= 0;
71 views::BoxLayout
* layout
= new views::BoxLayout(
72 views::BoxLayout::kVertical
, kHorizontal
, kVertical
, kPadding
);
73 layout
->set_main_axis_alignment(
74 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
75 layout
->set_cross_axis_alignment(
76 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH
);
77 SetLayoutManager(layout
);
79 views::View
* container
= new views::View
;
80 layout
= new views::BoxLayout(
81 views::BoxLayout::kHorizontal
, kHorizontal
, kVertical
, kPadding
);
82 layout
->set_main_axis_alignment(
83 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
84 container
->SetLayoutManager(layout
);
86 textfield_
= new views::Textfield();
87 textfield_
->set_placeholder_text(base::ASCIIToUTF16("Password"));
88 textfield_
->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD
);
89 textfield_
->set_default_width_in_chars(35);
90 container
->AddChildView(textfield_
);
92 connect_
= new views::BlueButton(this, base::ASCIIToUTF16("Connect"));
93 container
->AddChildView(connect_
);
95 cancel_
= new views::LabelButton(this, base::ASCIIToUTF16("Cancel"));
96 cancel_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
97 container
->AddChildView(cancel_
);
99 AddChildView(container
);
102 virtual ~PasswordView() {}
105 void Close(bool successful
) { callback_
.Run(successful
); }
107 void OnKnownError(const std::string
& error_name
,
108 scoped_ptr
<base::DictionaryValue
> error_data
) {
110 if (!error_data
->GetString(chromeos::network_handler::kDbusErrorMessage
,
112 message
= error_name
;
114 message
= std::string("Unknown error.");
116 error_msg_
= new views::Label();
117 error_msg_
->SetFontList(
118 error_msg_
->font_list().Derive(0, gfx::Font::BOLD
));
119 error_msg_
->SetEnabledColor(SK_ColorRED
);
121 error_msg_
->SetText(base::UTF8ToUTF16(message
));
122 if (!error_msg_
->parent()) {
123 AddChildView(error_msg_
);
125 parent_container_
->Layout();
126 ScrollRectToVisible(error_msg_
->bounds());
128 connect_
->SetEnabled(true);
131 void OnSetProfileSucceed(const base::string16
& password
) {
132 base::DictionaryValue properties
;
133 properties
.SetStringWithoutPathExpansion(shill::kPassphraseProperty
,
135 NetworkHandler::Get()->network_configuration_handler()->SetProperties(
136 network_
.service_path
,
138 base::Bind(&PasswordView::OnSetPropertiesSucceed
,
139 weak_ptr_
.GetWeakPtr()),
140 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()));
143 void OnSetPropertiesSucceed() {
144 const bool check_error_state
= false;
145 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
146 network_
.service_path
,
147 base::Bind(&PasswordView::OnConnectionSucceed
, weak_ptr_
.GetWeakPtr()),
148 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()),
152 void OnConnectionSucceed() { Close(true); }
155 virtual void ViewHierarchyChanged(
156 const views::View::ViewHierarchyChangedDetails
& details
) OVERRIDE
{
157 if (details
.is_add
&& details
.child
== this)
158 textfield_
->RequestFocus();
161 // views::ButtonListener:
162 virtual void ButtonPressed(views::Button
* sender
,
163 const ui::Event
& event
) OVERRIDE
{
164 if (sender
== connect_
) {
166 RemoveChildView(error_msg_
);
170 connect_
->SetEnabled(false);
171 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
172 network_
.service_path
,
173 NetworkProfileHandler::GetSharedProfilePath(),
174 base::Bind(&PasswordView::OnSetProfileSucceed
,
175 weak_ptr_
.GetWeakPtr(),
177 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()));
178 } else if (sender
== cancel_
) {
185 ui::NetworkInfo network_
;
186 base::Callback
<void(bool)> callback_
;
187 views::View
* parent_container_
;
189 views::BlueButton
* connect_
;
190 views::LabelButton
* cancel_
;
191 views::Textfield
* textfield_
;
192 views::Label
* error_msg_
;
193 base::WeakPtrFactory
<PasswordView
> weak_ptr_
;
195 DISALLOW_COPY_AND_ASSIGN(PasswordView
);
198 // A View that represents a single row in the network list. This row also
199 // contains the View for taking password for password-protected networks.
200 class NetworkRow
: public views::View
{
202 NetworkRow(const ui::NetworkInfo
& network
, views::View
* container
)
203 : network_(network
), container_(container
), weak_ptr_(this) {
204 SetBorder(views::Border::CreateEmptyBorder(10, 5, 10, 5));
206 new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0, 10));
210 virtual ~NetworkRow() {}
212 void Update(const ui::NetworkInfo
& network
) {
214 views::ImageView
* icon
= new views::ImageView();
215 icon
->SetImage(network
.image
);
216 icon
->SetBounds(0, 0, network
.image
.width(), network
.image
.height());
218 views::Label
* label
= new views::Label(network
.label
);
219 if (network
.highlight
)
220 label
->SetFontList(label
->font_list().Derive(0, gfx::Font::BOLD
));
224 AddChildView(password_view_
.get());
227 bool has_password_view() const { return password_view_
; }
230 void OnPasswordComplete(bool successful
) {
231 password_view_
.reset();
233 container_
->Layout();
234 ScrollRectToVisible(GetContentsBounds());
237 void ShowPasswordView(const std::string
& service_path
) {
238 const NetworkState
* network
=
239 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
244 // If this is not a wifi network that needs a password, then ignore.
245 if (network
->type() != shill::kTypeWifi
||
246 network
->security() == shill::kSecurityNone
) {
250 password_view_
.reset(new PasswordView(
252 base::Bind(&NetworkRow::OnPasswordComplete
, weak_ptr_
.GetWeakPtr()),
254 password_view_
->set_owned_by_client();
255 AddChildView(password_view_
.get());
256 PreferredSizeChanged();
257 container_
->Layout();
258 ScrollRectToVisible(password_view_
->bounds());
261 void OnNetworkConnectionError(const std::string
& service_path
,
262 const std::string
& error_name
,
263 scoped_ptr
<base::DictionaryValue
> error_data
) {
264 if (error_name
== NetworkConnectionHandler::kErrorConnectCanceled
)
266 if (error_name
== shill::kErrorBadPassphrase
||
267 error_name
== NetworkConnectionHandler::kErrorPassphraseRequired
||
268 error_name
== NetworkConnectionHandler::kErrorConfigurationRequired
||
269 error_name
== NetworkConnectionHandler::kErrorAuthenticationRequired
) {
270 ShowPasswordView(service_path
);
274 void ActivateNetwork() {
275 const chromeos::NetworkState
* network
=
276 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
277 network_
.service_path
);
280 if (network
->IsConnectedState()) {
281 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
282 network_
.service_path
,
284 chromeos::network_handler::ErrorCallback());
285 } else if (!network
->IsConnectingState()) {
286 // |network| is not connected, and not already trying to connect.
287 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
288 network_
.service_path
,
290 base::Bind(&NetworkRow::OnNetworkConnectionError
,
291 weak_ptr_
.GetWeakPtr(),
292 network_
.service_path
),
298 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
{
299 if (event
->type() != ui::ET_MOUSE_PRESSED
)
305 virtual void OnGestureEvent(ui::GestureEvent
* gesture
) OVERRIDE
{
306 if (gesture
->type() != ui::ET_GESTURE_TAP
)
309 gesture
->SetHandled();
312 ui::NetworkInfo network_
;
313 views::View
* container_
;
314 scoped_ptr
<views::View
> password_view_
;
315 base::WeakPtrFactory
<NetworkRow
> weak_ptr_
;
317 DISALLOW_COPY_AND_ASSIGN(NetworkRow
);
320 class NetworkSelector
: public ui::NetworkListDelegate
,
321 public chromeos::NetworkStateHandlerObserver
,
322 public ui::EventHandler
{
324 explicit NetworkSelector(aura::Window
* container
)
325 : background_view_(NULL
),
326 scroll_content_(NULL
),
328 network_list_(this) {
329 CreateWidget(container
);
332 NetworkHandler::Get()->network_state_handler()->RequestScan();
333 NetworkHandler::Get()->network_state_handler()->AddObserver(this,
337 virtual ~NetworkSelector() {
338 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
343 void CreateWidget(aura::Window
* container
) {
344 views::Widget::InitParams params
;
345 params
.type
= views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
;
346 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
347 params
.activatable
= views::Widget::InitParams::ACTIVATABLE_DEFAULT
;
348 params
.accept_events
= true;
349 params
.bounds
= gfx::Rect(container
->bounds().size());
350 params
.parent
= container
;
351 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
352 widget_
.reset(new views::Widget());
353 widget_
->Init(params
);
356 background_view_
= new views::View
;
357 background_view_
->set_background(
358 views::Background::CreateSolidBackground(kBackgroundColor
));
359 background_view_
->SetBorder(
360 views::Border::CreateEmptyBorder(100, 300, 300, 300));
361 background_view_
->SetLayoutManager(new views::FillLayout());
362 background_view_
->set_target_handler(this);
364 widget_
->SetContentsView(background_view_
);
367 void CreateNetworkList() {
368 const int kListHeight
= 500;
369 scroller_
= new views::ScrollView();
370 scroller_
->set_background(
371 views::Background::CreateSolidBackground(SK_ColorWHITE
));
372 scroller_
->SetBounds(0, 0, 400, kListHeight
);
374 scroll_content_
= new views::View
;
375 scroll_content_
->SetLayoutManager(
376 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0));
377 scroller_
->SetContents(scroll_content_
);
379 scroller_
->ClipHeightTo(kListHeight
, kListHeight
);
380 scroller_
->SetVerticalScrollBar(new views::OverlayScrollBar(false));
381 background_view_
->AddChildView(scroller_
);
383 background_view_
->Layout();
385 network_list_
.set_content_view(scroll_content_
);
388 void UpdateNetworkList() { network_list_
.UpdateNetworkList(); }
390 void Close() { delete this; }
392 // ui::NetworkListDelegate:
393 virtual views::View
* CreateViewForNetwork(
394 const ui::NetworkInfo
& info
) OVERRIDE
{
395 return new NetworkRow(info
, background_view_
);
398 virtual bool IsViewHovered(views::View
* view
) OVERRIDE
{
399 return static_cast<NetworkRow
*>(view
)->has_password_view();
402 virtual chromeos::NetworkTypePattern
GetNetworkTypePattern() const OVERRIDE
{
403 return chromeos::NetworkTypePattern::NonVirtual();
406 virtual void UpdateViewForNetwork(views::View
* view
,
407 const ui::NetworkInfo
& info
) OVERRIDE
{
408 static_cast<NetworkRow
*>(view
)->Update(info
);
411 virtual views::Label
* CreateInfoLabel() OVERRIDE
{
412 views::Label
* label
= new views::Label();
416 virtual void RelayoutScrollList() OVERRIDE
{ scroller_
->Layout(); }
418 // chromeos::NetworkStateHandlerObserver:
419 virtual void NetworkListChanged() OVERRIDE
{ UpdateNetworkList(); }
421 virtual void DeviceListChanged() OVERRIDE
{}
423 virtual void DefaultNetworkChanged(
424 const chromeos::NetworkState
* network
) OVERRIDE
{}
426 virtual void NetworkConnectionStateChanged(
427 const chromeos::NetworkState
* network
) OVERRIDE
{}
429 virtual void NetworkPropertiesUpdated(
430 const chromeos::NetworkState
* network
) OVERRIDE
{}
433 virtual void OnMouseEvent(ui::MouseEvent
* mouse
) OVERRIDE
{
434 CHECK_EQ(background_view_
, mouse
->target());
435 if (mouse
->type() == ui::ET_MOUSE_PRESSED
&& !mouse
->handled()) {
441 virtual void OnGestureEvent(ui::GestureEvent
* gesture
) OVERRIDE
{
442 CHECK_EQ(background_view_
, gesture
->target());
443 if (gesture
->type() == ui::ET_GESTURE_TAP
&& !gesture
->handled()) {
445 gesture
->SetHandled();
449 scoped_ptr
<views::Widget
> widget_
;
450 views::View
* background_view_
;
451 views::View
* scroll_content_
;
452 views::ScrollView
* scroller_
;
454 views::View
* connect_
;
456 ui::NetworkListView network_list_
;
458 DISALLOW_COPY_AND_ASSIGN(NetworkSelector
);
465 void CreateNetworkSelector(aura::Window
* container
) {
466 new NetworkSelector(container
);
469 } // namespace athena