Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / athena / main / debug / network_selector.cc
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.
4
5 #include "athena/main/debug/network_selector.h"
6
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"
41
42 using chromeos::NetworkConfigurationHandler;
43 using chromeos::NetworkConnectionHandler;
44 using chromeos::NetworkHandler;
45 using chromeos::NetworkProfileHandler;
46 using chromeos::NetworkState;
47
48 namespace {
49
50 const int kBackgroundColor = SkColorSetARGB(0x7f, 0, 0, 0);
51
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 {
55  public:
56   PasswordView(const ui::NetworkInfo& network,
57                const base::Callback<void(bool)>& callback,
58                views::View* parent_container)
59       : network_(network),
60         callback_(callback),
61         parent_container_(parent_container),
62         connect_(NULL),
63         cancel_(NULL),
64         textfield_(NULL),
65         error_msg_(NULL),
66         weak_ptr_(this) {
67     const int kHorizontal = 5;
68     const int kVertical = 0;
69     const int kPadding = 0;
70
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);
78
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);
85
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_);
91
92     connect_ = new views::BlueButton(this, base::ASCIIToUTF16("Connect"));
93     container->AddChildView(connect_);
94
95     cancel_ = new views::LabelButton(this, base::ASCIIToUTF16("Cancel"));
96     cancel_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
97     container->AddChildView(cancel_);
98
99     AddChildView(container);
100   }
101
102   virtual ~PasswordView() {}
103
104  private:
105   void Close(bool successful) { callback_.Run(successful); }
106
107   void OnKnownError(const std::string& error_name,
108                     scoped_ptr<base::DictionaryValue> error_data) {
109     std::string message;
110     if (!error_data->GetString(chromeos::network_handler::kDbusErrorMessage,
111                                &message))
112       message = error_name;
113     if (message.empty())
114       message = std::string("Unknown error.");
115     if (!error_msg_) {
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);
120     }
121     error_msg_->SetText(base::UTF8ToUTF16(message));
122     if (!error_msg_->parent()) {
123       AddChildView(error_msg_);
124       InvalidateLayout();
125       parent_container_->Layout();
126       ScrollRectToVisible(error_msg_->bounds());
127     }
128     connect_->SetEnabled(true);
129   }
130
131   void OnSetProfileSucceed(const base::string16& password) {
132     base::DictionaryValue properties;
133     properties.SetStringWithoutPathExpansion(shill::kPassphraseProperty,
134                                              textfield_->text());
135     NetworkHandler::Get()->network_configuration_handler()->SetProperties(
136         network_.service_path,
137         properties,
138         base::Bind(&PasswordView::OnSetPropertiesSucceed,
139                    weak_ptr_.GetWeakPtr()),
140         base::Bind(&PasswordView::OnKnownError, weak_ptr_.GetWeakPtr()));
141   }
142
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()),
149         check_error_state);
150   }
151
152   void OnConnectionSucceed() { Close(true); }
153
154   // views::View:
155   virtual void ViewHierarchyChanged(
156       const views::View::ViewHierarchyChangedDetails& details) OVERRIDE {
157     if (details.is_add && details.child == this)
158       textfield_->RequestFocus();
159   }
160
161   // views::ButtonListener:
162   virtual void ButtonPressed(views::Button* sender,
163                              const ui::Event& event) OVERRIDE {
164     if (sender == connect_) {
165       if (error_msg_) {
166         RemoveChildView(error_msg_);
167         delete error_msg_;
168         error_msg_ = NULL;
169       }
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(),
176                      textfield_->text()),
177           base::Bind(&PasswordView::OnKnownError, weak_ptr_.GetWeakPtr()));
178     } else if (sender == cancel_) {
179       Close(false);
180     } else {
181       NOTREACHED();
182     }
183   }
184
185   ui::NetworkInfo network_;
186   base::Callback<void(bool)> callback_;
187   views::View* parent_container_;
188
189   views::BlueButton* connect_;
190   views::LabelButton* cancel_;
191   views::Textfield* textfield_;
192   views::Label* error_msg_;
193   base::WeakPtrFactory<PasswordView> weak_ptr_;
194
195   DISALLOW_COPY_AND_ASSIGN(PasswordView);
196 };
197
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 {
201  public:
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));
205     SetLayoutManager(
206         new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 10));
207     Update(network);
208   }
209
210   virtual ~NetworkRow() {}
211
212   void Update(const ui::NetworkInfo& network) {
213     network_ = network;
214     views::ImageView* icon = new views::ImageView();
215     icon->SetImage(network.image);
216     icon->SetBounds(0, 0, network.image.width(), network.image.height());
217
218     views::Label* label = new views::Label(network.label);
219     if (network.highlight)
220       label->SetFontList(label->font_list().Derive(0, gfx::Font::BOLD));
221     AddChildView(icon);
222     AddChildView(label);
223     if (password_view_)
224       AddChildView(password_view_.get());
225   }
226
227   bool has_password_view() const { return password_view_; }
228
229  private:
230   void OnPasswordComplete(bool successful) {
231     password_view_.reset();
232     InvalidateLayout();
233     container_->Layout();
234     ScrollRectToVisible(GetContentsBounds());
235   }
236
237   void ShowPasswordView(const std::string& service_path) {
238     const NetworkState* network =
239         NetworkHandler::Get()->network_state_handler()->GetNetworkState(
240             service_path);
241     if (!network)
242       return;
243
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) {
247       return;
248     }
249
250     password_view_.reset(new PasswordView(
251         network_,
252         base::Bind(&NetworkRow::OnPasswordComplete, weak_ptr_.GetWeakPtr()),
253         container_));
254     password_view_->set_owned_by_client();
255     AddChildView(password_view_.get());
256     PreferredSizeChanged();
257     container_->Layout();
258     ScrollRectToVisible(password_view_->bounds());
259   }
260
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)
265       return;
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);
271     }
272   }
273
274   void ActivateNetwork() {
275     const chromeos::NetworkState* network =
276         NetworkHandler::Get()->network_state_handler()->GetNetworkState(
277             network_.service_path);
278     if (!network)
279       return;
280     if (network->IsConnectedState()) {
281       NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
282           network_.service_path,
283           base::Closure(),
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,
289           base::Closure(),
290           base::Bind(&NetworkRow::OnNetworkConnectionError,
291                      weak_ptr_.GetWeakPtr(),
292                      network_.service_path),
293           false);
294     }
295   }
296
297   // views::View:
298   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
299     if (event->type() != ui::ET_MOUSE_PRESSED)
300       return;
301     ActivateNetwork();
302     event->SetHandled();
303   }
304
305   virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
306     if (gesture->type() != ui::ET_GESTURE_TAP)
307       return;
308     ActivateNetwork();
309     gesture->SetHandled();
310   }
311
312   ui::NetworkInfo network_;
313   views::View* container_;
314   base::WeakPtrFactory<NetworkRow> weak_ptr_;
315   scoped_ptr<views::View> password_view_;
316
317   DISALLOW_COPY_AND_ASSIGN(NetworkRow);
318 };
319
320 class NetworkSelector : public ui::NetworkListDelegate,
321                         public chromeos::NetworkStateHandlerObserver,
322                         public ui::EventHandler {
323  public:
324   explicit NetworkSelector(aura::Window* container)
325       : background_view_(NULL),
326         scroll_content_(NULL),
327         scroller_(NULL),
328         network_list_(this) {
329     CreateWidget(container);
330     CreateNetworkList();
331
332     NetworkHandler::Get()->network_state_handler()->RequestScan();
333     NetworkHandler::Get()->network_state_handler()->AddObserver(this,
334                                                                 FROM_HERE);
335   }
336
337   virtual ~NetworkSelector() {
338     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
339                                                                    FROM_HERE);
340   }
341
342  private:
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);
354     widget_->Show();
355
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);
363
364     widget_->SetContentsView(background_view_);
365   }
366
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);
373
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_);
378
379     scroller_->ClipHeightTo(kListHeight, kListHeight);
380     scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
381     background_view_->AddChildView(scroller_);
382
383     background_view_->Layout();
384
385     network_list_.set_content_view(scroll_content_);
386   }
387
388   void UpdateNetworkList() { network_list_.UpdateNetworkList(); }
389
390   void Close() { delete this; }
391
392   // ui::NetworkListDelegate:
393   virtual views::View* CreateViewForNetwork(
394       const ui::NetworkInfo& info) OVERRIDE {
395     return new NetworkRow(info, background_view_);
396   }
397
398   virtual bool IsViewHovered(views::View* view) OVERRIDE {
399     return static_cast<NetworkRow*>(view)->has_password_view();
400   }
401
402   virtual chromeos::NetworkTypePattern GetNetworkTypePattern() const OVERRIDE {
403     return chromeos::NetworkTypePattern::NonVirtual();
404   }
405
406   virtual void UpdateViewForNetwork(views::View* view,
407                                     const ui::NetworkInfo& info) OVERRIDE {
408     static_cast<NetworkRow*>(view)->Update(info);
409   }
410
411   virtual views::Label* CreateInfoLabel() OVERRIDE {
412     views::Label* label = new views::Label();
413     return label;
414   }
415
416   virtual void RelayoutScrollList() OVERRIDE { scroller_->Layout(); }
417
418   // chromeos::NetworkStateHandlerObserver:
419   virtual void NetworkListChanged() OVERRIDE { UpdateNetworkList(); }
420
421   virtual void DeviceListChanged() OVERRIDE {}
422
423   virtual void DefaultNetworkChanged(
424       const chromeos::NetworkState* network) OVERRIDE {}
425
426   virtual void NetworkConnectionStateChanged(
427       const chromeos::NetworkState* network) OVERRIDE {}
428
429   virtual void NetworkPropertiesUpdated(
430       const chromeos::NetworkState* network) OVERRIDE {}
431
432   // ui::EventHandler:
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()) {
436       Close();
437       mouse->SetHandled();
438     }
439   }
440
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()) {
444       Close();
445       gesture->SetHandled();
446     }
447   }
448
449   scoped_ptr<views::Widget> widget_;
450   views::View* background_view_;
451   views::View* scroll_content_;
452   views::ScrollView* scroller_;
453
454   views::View* connect_;
455
456   ui::NetworkListView network_list_;
457
458   DISALLOW_COPY_AND_ASSIGN(NetworkSelector);
459 };
460
461 }  // namespace
462
463 namespace debug {
464
465 void CreateNetworkSelector(aura::Window* container) {
466   new NetworkSelector(container);
467 }
468
469 }  // namespace debug