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 "athena/screen/public/screen_manager.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chromeos/network/network_configuration_handler.h"
11 #include "chromeos/network/network_connection_handler.h"
12 #include "chromeos/network/network_handler.h"
13 #include "chromeos/network/network_profile_handler.h"
14 #include "chromeos/network/network_state.h"
15 #include "chromeos/network/network_state_handler.h"
16 #include "chromeos/network/network_state_handler_observer.h"
17 #include "chromeos/network/network_type_pattern.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
19 #include "ui/aura/window.h"
20 #include "ui/chromeos/network/network_icon.h"
21 #include "ui/chromeos/network/network_info.h"
22 #include "ui/chromeos/network/network_list.h"
23 #include "ui/chromeos/network/network_list_delegate.h"
24 #include "ui/compositor/layer.h"
25 #include "ui/gfx/canvas.h"
26 #include "ui/gfx/font.h"
27 #include "ui/gfx/font_list.h"
28 #include "ui/gfx/geometry/rect.h"
29 #include "ui/gfx/text_constants.h"
30 #include "ui/views/background.h"
31 #include "ui/views/border.h"
32 #include "ui/views/controls/button/blue_button.h"
33 #include "ui/views/controls/button/button.h"
34 #include "ui/views/controls/image_view.h"
35 #include "ui/views/controls/label.h"
36 #include "ui/views/controls/scroll_view.h"
37 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
38 #include "ui/views/controls/textfield/textfield.h"
39 #include "ui/views/layout/box_layout.h"
40 #include "ui/views/layout/fill_layout.h"
41 #include "ui/views/widget/widget.h"
42 #include "ui/views/window/dialog_delegate.h"
44 using chromeos::NetworkConfigurationHandler
;
45 using chromeos::NetworkConfigurationObserver
;
46 using chromeos::NetworkConnectionHandler
;
47 using chromeos::NetworkHandler
;
48 using chromeos::NetworkProfileHandler
;
49 using chromeos::NetworkState
;
53 // The View for the user to enter the password for connceting to a network. This
54 // view also shows an error message if the network connection fails.
55 class PasswordView
: public views::View
, public views::ButtonListener
{
57 PasswordView(const ui::NetworkInfo
& network
,
58 const base::Callback
<void(bool)>& callback
)
66 const int kHorizontal
= 5;
67 const int kVertical
= 0;
68 const int kPadding
= 0;
70 views::BoxLayout
* layout
= new views::BoxLayout(
71 views::BoxLayout::kVertical
, kHorizontal
, kVertical
, kPadding
);
72 layout
->set_main_axis_alignment(
73 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
74 layout
->set_cross_axis_alignment(
75 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH
);
76 SetLayoutManager(layout
);
78 views::View
* container
= new views::View
;
79 layout
= new views::BoxLayout(
80 views::BoxLayout::kHorizontal
, kHorizontal
, kVertical
, kPadding
);
81 layout
->set_main_axis_alignment(
82 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
83 container
->SetLayoutManager(layout
);
85 textfield_
= new views::Textfield();
86 textfield_
->set_placeholder_text(base::ASCIIToUTF16("Password"));
87 textfield_
->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD
);
88 textfield_
->set_default_width_in_chars(35);
89 container
->AddChildView(textfield_
);
91 connect_
= new views::BlueButton(this, base::ASCIIToUTF16("Connect"));
92 container
->AddChildView(connect_
);
94 cancel_
= new views::LabelButton(this, base::ASCIIToUTF16("Cancel"));
95 cancel_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
96 container
->AddChildView(cancel_
);
98 AddChildView(container
);
101 ~PasswordView() override
{}
104 void CloseDialog(bool successful
) { callback_
.Run(successful
); }
106 void OnKnownError(const std::string
& error_name
,
107 scoped_ptr
<base::DictionaryValue
> error_data
) {
109 if (!error_data
->GetString(chromeos::network_handler::kDbusErrorMessage
,
111 message
= error_name
;
113 message
= std::string("Unknown error.");
115 error_msg_
= new views::Label();
116 error_msg_
->SetFontList(
117 error_msg_
->font_list().Derive(0, gfx::Font::BOLD
));
118 error_msg_
->SetEnabledColor(SK_ColorRED
);
120 error_msg_
->SetText(base::UTF8ToUTF16(message
));
121 if (!error_msg_
->parent()) {
122 AddChildView(error_msg_
);
124 GetWidget()->GetRootView()->Layout();
125 ScrollRectToVisible(error_msg_
->bounds());
127 connect_
->SetEnabled(true);
130 void OnSetProfileSucceed(const base::string16
& password
) {
131 base::DictionaryValue properties
;
132 properties
.SetStringWithoutPathExpansion(shill::kPassphraseProperty
,
134 NetworkHandler::Get()->network_configuration_handler()->SetProperties(
135 network_
.service_path
,
137 NetworkConfigurationObserver::SOURCE_USER_ACTION
,
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() { CloseDialog(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_
);
168 error_msg_
= nullptr;
170 connect_
->SetEnabled(false);
171 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
172 network_
.service_path
,
173 NetworkProfileHandler::GetSharedProfilePath(),
174 NetworkConfigurationObserver::SOURCE_USER_ACTION
,
175 base::Bind(&PasswordView::OnSetProfileSucceed
,
176 weak_ptr_
.GetWeakPtr(),
178 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()));
179 } else if (sender
== cancel_
) {
186 ui::NetworkInfo network_
;
187 base::Callback
<void(bool)> callback_
;
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
)
203 : network_(network
), weak_ptr_(this) {
204 SetBorder(views::Border::CreateEmptyBorder(10, 5, 10, 5));
206 new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0, 10));
210 ~NetworkRow() override
{}
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 GetWidget()->GetRootView()->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_class() == shill::kSecurityNone
) {
250 password_view_
.reset(new PasswordView(
252 base::Bind(&NetworkRow::OnPasswordComplete
, weak_ptr_
.GetWeakPtr())));
253 password_view_
->set_owned_by_client();
254 AddChildView(password_view_
.get());
255 PreferredSizeChanged();
256 GetWidget()->GetRootView()->Layout();
257 ScrollRectToVisible(password_view_
->bounds());
260 void OnNetworkConnectionError(const std::string
& service_path
,
261 const std::string
& error_name
,
262 scoped_ptr
<base::DictionaryValue
> error_data
) {
263 if (error_name
== NetworkConnectionHandler::kErrorConnectCanceled
)
265 if (error_name
== shill::kErrorBadPassphrase
||
266 error_name
== NetworkConnectionHandler::kErrorPassphraseRequired
||
267 error_name
== NetworkConnectionHandler::kErrorConfigurationRequired
||
268 error_name
== NetworkConnectionHandler::kErrorAuthenticationRequired
) {
269 ShowPasswordView(service_path
);
273 void ActivateNetwork() {
274 const chromeos::NetworkState
* network
=
275 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
276 network_
.service_path
);
279 if (network
->IsConnectedState()) {
280 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
281 network_
.service_path
,
283 chromeos::network_handler::ErrorCallback());
284 } else if (!network
->IsConnectingState()) {
285 // |network| is not connected, and not already trying to connect.
286 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
287 network_
.service_path
,
289 base::Bind(&NetworkRow::OnNetworkConnectionError
,
290 weak_ptr_
.GetWeakPtr(),
291 network_
.service_path
),
297 virtual void OnMouseEvent(ui::MouseEvent
* event
) override
{
298 if (event
->type() != ui::ET_MOUSE_PRESSED
)
304 virtual void OnGestureEvent(ui::GestureEvent
* gesture
) override
{
305 if (gesture
->type() != ui::ET_GESTURE_TAP
)
308 gesture
->SetHandled();
311 ui::NetworkInfo network_
;
312 scoped_ptr
<views::View
> password_view_
;
313 base::WeakPtrFactory
<NetworkRow
> weak_ptr_
;
315 DISALLOW_COPY_AND_ASSIGN(NetworkRow
);
318 class NetworkSelector
: public ui::NetworkListDelegate
,
319 public chromeos::NetworkStateHandlerObserver
,
320 public views::DialogDelegate
{
323 : scroll_content_(nullptr), scroller_(nullptr), network_list_(this) {
327 NetworkHandler::Get()->network_state_handler()->RequestScan();
328 NetworkHandler::Get()->network_state_handler()->AddObserver(this,
332 ~NetworkSelector() override
{
333 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
338 void CreateWidget() {
339 // Same as CreateDialogWidgetWithBounds() with an empty |bounds|.
340 views::Widget
* widget
= views::DialogDelegate::CreateDialogWidget(
341 this, athena::ScreenManager::Get()->GetContext(), nullptr);
343 widget
->CenterWindow(gfx::Size(400, 400));
346 void CreateNetworkList() {
347 const int kListHeight
= 400;
348 scroller_
= new views::ScrollView();
349 scroller_
->set_background(
350 views::Background::CreateSolidBackground(SK_ColorWHITE
));
352 scroll_content_
= new views::View
;
353 scroll_content_
->SetLayoutManager(
354 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0));
355 scroller_
->SetContents(scroll_content_
);
357 scroller_
->ClipHeightTo(kListHeight
, kListHeight
);
358 scroller_
->SetVerticalScrollBar(new views::OverlayScrollBar(false));
360 network_list_
.set_content_view(scroll_content_
);
363 void UpdateNetworkList() { network_list_
.UpdateNetworkList(); }
365 // ui::NetworkListDelegate:
366 virtual views::View
* CreateViewForNetwork(
367 const ui::NetworkInfo
& info
) override
{
368 return new NetworkRow(info
);
371 virtual bool IsViewHovered(views::View
* view
) override
{
372 return static_cast<NetworkRow
*>(view
)->has_password_view();
375 virtual chromeos::NetworkTypePattern
GetNetworkTypePattern() const override
{
376 return chromeos::NetworkTypePattern::NonVirtual();
379 virtual void UpdateViewForNetwork(views::View
* view
,
380 const ui::NetworkInfo
& info
) override
{
381 static_cast<NetworkRow
*>(view
)->Update(info
);
384 virtual views::Label
* CreateInfoLabel() override
{
385 views::Label
* label
= new views::Label();
389 virtual void RelayoutScrollList() override
{ scroller_
->Layout(); }
391 // chromeos::NetworkStateHandlerObserver:
392 virtual void NetworkListChanged() override
{ UpdateNetworkList(); }
394 virtual void DeviceListChanged() override
{}
396 virtual void DefaultNetworkChanged(
397 const chromeos::NetworkState
* network
) override
{}
399 virtual void NetworkConnectionStateChanged(
400 const chromeos::NetworkState
* network
) override
{}
402 virtual void NetworkPropertiesUpdated(
403 const chromeos::NetworkState
* network
) override
{}
405 // views::DialogDelegate:
406 virtual ui::ModalType
GetModalType() const override
{
407 return ui::MODAL_TYPE_SYSTEM
;
409 virtual void DeleteDelegate() override
{ delete this; }
410 virtual views::Widget
* GetWidget() override
{ return scroller_
->GetWidget(); }
411 virtual const views::Widget
* GetWidget() const override
{
412 return scroller_
->GetWidget();
414 virtual views::View
* GetContentsView() override
{ return scroller_
; }
415 virtual int GetDialogButtons() const override
{ return ui::DIALOG_BUTTON_OK
; }
416 virtual bool Close() override
{ return true; }
418 views::View
* scroll_content_
;
419 views::ScrollView
* scroller_
;
421 views::View
* connect_
;
423 ui::NetworkListView network_list_
;
425 DISALLOW_COPY_AND_ASSIGN(NetworkSelector
);
432 void CreateNetworkSelector() {
433 new NetworkSelector();
436 } // namespace athena