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::NetworkConnectionHandler
;
46 using chromeos::NetworkHandler
;
47 using chromeos::NetworkProfileHandler
;
48 using chromeos::NetworkState
;
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
)
65 const int kHorizontal
= 5;
66 const int kVertical
= 0;
67 const int kPadding
= 0;
69 views::BoxLayout
* layout
= new views::BoxLayout(
70 views::BoxLayout::kVertical
, kHorizontal
, kVertical
, kPadding
);
71 layout
->set_main_axis_alignment(
72 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
73 layout
->set_cross_axis_alignment(
74 views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH
);
75 SetLayoutManager(layout
);
77 views::View
* container
= new views::View
;
78 layout
= new views::BoxLayout(
79 views::BoxLayout::kHorizontal
, kHorizontal
, kVertical
, kPadding
);
80 layout
->set_main_axis_alignment(
81 views::BoxLayout::MAIN_AXIS_ALIGNMENT_START
);
82 container
->SetLayoutManager(layout
);
84 textfield_
= new views::Textfield();
85 textfield_
->set_placeholder_text(base::ASCIIToUTF16("Password"));
86 textfield_
->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD
);
87 textfield_
->set_default_width_in_chars(35);
88 container
->AddChildView(textfield_
);
90 connect_
= new views::BlueButton(this, base::ASCIIToUTF16("Connect"));
91 container
->AddChildView(connect_
);
93 cancel_
= new views::LabelButton(this, base::ASCIIToUTF16("Cancel"));
94 cancel_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
95 container
->AddChildView(cancel_
);
97 AddChildView(container
);
100 virtual ~PasswordView() {}
103 void CloseDialog(bool successful
) { callback_
.Run(successful
); }
105 void OnKnownError(const std::string
& error_name
,
106 scoped_ptr
<base::DictionaryValue
> error_data
) {
108 if (!error_data
->GetString(chromeos::network_handler::kDbusErrorMessage
,
110 message
= error_name
;
112 message
= std::string("Unknown error.");
114 error_msg_
= new views::Label();
115 error_msg_
->SetFontList(
116 error_msg_
->font_list().Derive(0, gfx::Font::BOLD
));
117 error_msg_
->SetEnabledColor(SK_ColorRED
);
119 error_msg_
->SetText(base::UTF8ToUTF16(message
));
120 if (!error_msg_
->parent()) {
121 AddChildView(error_msg_
);
123 GetWidget()->GetRootView()->Layout();
124 ScrollRectToVisible(error_msg_
->bounds());
126 connect_
->SetEnabled(true);
129 void OnSetProfileSucceed(const base::string16
& password
) {
130 base::DictionaryValue properties
;
131 properties
.SetStringWithoutPathExpansion(shill::kPassphraseProperty
,
133 NetworkHandler::Get()->network_configuration_handler()->SetProperties(
134 network_
.service_path
,
136 base::Bind(&PasswordView::OnSetPropertiesSucceed
,
137 weak_ptr_
.GetWeakPtr()),
138 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()));
141 void OnSetPropertiesSucceed() {
142 const bool check_error_state
= false;
143 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
144 network_
.service_path
,
145 base::Bind(&PasswordView::OnConnectionSucceed
, weak_ptr_
.GetWeakPtr()),
146 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()),
150 void OnConnectionSucceed() { CloseDialog(true); }
153 virtual void ViewHierarchyChanged(
154 const views::View::ViewHierarchyChangedDetails
& details
) override
{
155 if (details
.is_add
&& details
.child
== this)
156 textfield_
->RequestFocus();
159 // views::ButtonListener:
160 virtual void ButtonPressed(views::Button
* sender
,
161 const ui::Event
& event
) override
{
162 if (sender
== connect_
) {
164 RemoveChildView(error_msg_
);
168 connect_
->SetEnabled(false);
169 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
170 network_
.service_path
,
171 NetworkProfileHandler::GetSharedProfilePath(),
172 base::Bind(&PasswordView::OnSetProfileSucceed
,
173 weak_ptr_
.GetWeakPtr(),
175 base::Bind(&PasswordView::OnKnownError
, weak_ptr_
.GetWeakPtr()));
176 } else if (sender
== cancel_
) {
183 ui::NetworkInfo network_
;
184 base::Callback
<void(bool)> callback_
;
186 views::BlueButton
* connect_
;
187 views::LabelButton
* cancel_
;
188 views::Textfield
* textfield_
;
189 views::Label
* error_msg_
;
190 base::WeakPtrFactory
<PasswordView
> weak_ptr_
;
192 DISALLOW_COPY_AND_ASSIGN(PasswordView
);
195 // A View that represents a single row in the network list. This row also
196 // contains the View for taking password for password-protected networks.
197 class NetworkRow
: public views::View
{
199 NetworkRow(const ui::NetworkInfo
& network
)
200 : network_(network
), weak_ptr_(this) {
201 SetBorder(views::Border::CreateEmptyBorder(10, 5, 10, 5));
203 new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0, 10));
207 virtual ~NetworkRow() {}
209 void Update(const ui::NetworkInfo
& network
) {
211 views::ImageView
* icon
= new views::ImageView();
212 icon
->SetImage(network
.image
);
213 icon
->SetBounds(0, 0, network
.image
.width(), network
.image
.height());
215 views::Label
* label
= new views::Label(network
.label
);
216 if (network
.highlight
)
217 label
->SetFontList(label
->font_list().Derive(0, gfx::Font::BOLD
));
221 AddChildView(password_view_
.get());
224 bool has_password_view() const { return password_view_
; }
227 void OnPasswordComplete(bool successful
) {
228 password_view_
.reset();
230 GetWidget()->GetRootView()->Layout();
231 ScrollRectToVisible(GetContentsBounds());
234 void ShowPasswordView(const std::string
& service_path
) {
235 const NetworkState
* network
=
236 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
241 // If this is not a wifi network that needs a password, then ignore.
242 if (network
->type() != shill::kTypeWifi
||
243 network
->security() == shill::kSecurityNone
) {
247 password_view_
.reset(new PasswordView(
249 base::Bind(&NetworkRow::OnPasswordComplete
, weak_ptr_
.GetWeakPtr())));
250 password_view_
->set_owned_by_client();
251 AddChildView(password_view_
.get());
252 PreferredSizeChanged();
253 GetWidget()->GetRootView()->Layout();
254 ScrollRectToVisible(password_view_
->bounds());
257 void OnNetworkConnectionError(const std::string
& service_path
,
258 const std::string
& error_name
,
259 scoped_ptr
<base::DictionaryValue
> error_data
) {
260 if (error_name
== NetworkConnectionHandler::kErrorConnectCanceled
)
262 if (error_name
== shill::kErrorBadPassphrase
||
263 error_name
== NetworkConnectionHandler::kErrorPassphraseRequired
||
264 error_name
== NetworkConnectionHandler::kErrorConfigurationRequired
||
265 error_name
== NetworkConnectionHandler::kErrorAuthenticationRequired
) {
266 ShowPasswordView(service_path
);
270 void ActivateNetwork() {
271 const chromeos::NetworkState
* network
=
272 NetworkHandler::Get()->network_state_handler()->GetNetworkState(
273 network_
.service_path
);
276 if (network
->IsConnectedState()) {
277 NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
278 network_
.service_path
,
280 chromeos::network_handler::ErrorCallback());
281 } else if (!network
->IsConnectingState()) {
282 // |network| is not connected, and not already trying to connect.
283 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
284 network_
.service_path
,
286 base::Bind(&NetworkRow::OnNetworkConnectionError
,
287 weak_ptr_
.GetWeakPtr(),
288 network_
.service_path
),
294 virtual void OnMouseEvent(ui::MouseEvent
* event
) override
{
295 if (event
->type() != ui::ET_MOUSE_PRESSED
)
301 virtual void OnGestureEvent(ui::GestureEvent
* gesture
) override
{
302 if (gesture
->type() != ui::ET_GESTURE_TAP
)
305 gesture
->SetHandled();
308 ui::NetworkInfo network_
;
309 scoped_ptr
<views::View
> password_view_
;
310 base::WeakPtrFactory
<NetworkRow
> weak_ptr_
;
312 DISALLOW_COPY_AND_ASSIGN(NetworkRow
);
315 class NetworkSelector
: public ui::NetworkListDelegate
,
316 public chromeos::NetworkStateHandlerObserver
,
317 public views::DialogDelegate
{
320 : scroll_content_(NULL
), scroller_(NULL
), network_list_(this) {
324 NetworkHandler::Get()->network_state_handler()->RequestScan();
325 NetworkHandler::Get()->network_state_handler()->AddObserver(this,
329 virtual ~NetworkSelector() {
330 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
335 void CreateWidget() {
336 // Same as CreateDialogWidgetWithBounds() with an empty |bounds|.
337 views::Widget
* widget
= views::DialogDelegate::CreateDialogWidget(
338 this, athena::ScreenManager::Get()->GetContext(), NULL
);
340 widget
->CenterWindow(gfx::Size(400, 400));
343 void CreateNetworkList() {
344 const int kListHeight
= 400;
345 scroller_
= new views::ScrollView();
346 scroller_
->set_background(
347 views::Background::CreateSolidBackground(SK_ColorWHITE
));
349 scroll_content_
= new views::View
;
350 scroll_content_
->SetLayoutManager(
351 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0));
352 scroller_
->SetContents(scroll_content_
);
354 scroller_
->ClipHeightTo(kListHeight
, kListHeight
);
355 scroller_
->SetVerticalScrollBar(new views::OverlayScrollBar(false));
357 network_list_
.set_content_view(scroll_content_
);
360 void UpdateNetworkList() { network_list_
.UpdateNetworkList(); }
362 // ui::NetworkListDelegate:
363 virtual views::View
* CreateViewForNetwork(
364 const ui::NetworkInfo
& info
) override
{
365 return new NetworkRow(info
);
368 virtual bool IsViewHovered(views::View
* view
) override
{
369 return static_cast<NetworkRow
*>(view
)->has_password_view();
372 virtual chromeos::NetworkTypePattern
GetNetworkTypePattern() const override
{
373 return chromeos::NetworkTypePattern::NonVirtual();
376 virtual void UpdateViewForNetwork(views::View
* view
,
377 const ui::NetworkInfo
& info
) override
{
378 static_cast<NetworkRow
*>(view
)->Update(info
);
381 virtual views::Label
* CreateInfoLabel() override
{
382 views::Label
* label
= new views::Label();
386 virtual void RelayoutScrollList() override
{ scroller_
->Layout(); }
388 // chromeos::NetworkStateHandlerObserver:
389 virtual void NetworkListChanged() override
{ UpdateNetworkList(); }
391 virtual void DeviceListChanged() override
{}
393 virtual void DefaultNetworkChanged(
394 const chromeos::NetworkState
* network
) override
{}
396 virtual void NetworkConnectionStateChanged(
397 const chromeos::NetworkState
* network
) override
{}
399 virtual void NetworkPropertiesUpdated(
400 const chromeos::NetworkState
* network
) override
{}
402 // views::DialogDelegate:
403 virtual ui::ModalType
GetModalType() const override
{
404 return ui::MODAL_TYPE_SYSTEM
;
406 virtual void DeleteDelegate() override
{ delete this; }
407 virtual views::Widget
* GetWidget() override
{ return scroller_
->GetWidget(); }
408 virtual const views::Widget
* GetWidget() const override
{
409 return scroller_
->GetWidget();
411 virtual views::View
* GetContentsView() override
{ return scroller_
; }
412 virtual int GetDialogButtons() const override
{ return ui::DIALOG_BUTTON_OK
; }
413 virtual bool Close() override
{ return true; }
415 views::View
* scroll_content_
;
416 views::ScrollView
* scroller_
;
418 views::View
* connect_
;
420 ui::NetworkListView network_list_
;
422 DISALLOW_COPY_AND_ASSIGN(NetworkSelector
);
429 void CreateNetworkSelector() {
430 new NetworkSelector();
433 } // namespace athena