1// Copyright (c) 2010 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 "chrome/browser/chromeos/login/network_screen.h"
6
7#include "base/logging.h"
8#include "base/string16.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/browser/chromeos/cros/cros_library.h"
11#include "chrome/browser/chromeos/login/background_view.h"
12#include "chrome/browser/chromeos/login/helper.h"
13#include "chrome/browser/chromeos/login/help_app_launcher.h"
14#include "chrome/browser/chromeos/login/login_utils.h"
15#include "chrome/browser/chromeos/login/network_selection_view.h"
16#include "chrome/browser/chromeos/login/screen_observer.h"
17#include "grit/chromium_strings.h"
18#include "grit/generated_resources.h"
19#include "grit/theme_resources.h"
20#include "ui/base/l10n/l10n_util.h"
21#include "ui/base/resource/resource_bundle.h"
22#include "views/controls/menu/menu_2.h"
23#include "views/widget/widget.h"
24#include "views/window/window.h"
25
26
27namespace {
28
29// Time in seconds for connection timeout.
30const int kConnectionTimeoutSec = 15;
31
32// Considering 10px shadow from each side & welcome title height at 30px.
33const int kWelcomeScreenWidth = 580;
34const int kWelcomeScreenHeight = 335;
35
36}  // namespace
37
38namespace chromeos {
39
40///////////////////////////////////////////////////////////////////////////////
41// NetworkScreen, public:
42
43NetworkScreen::NetworkScreen(WizardScreenDelegate* delegate)
44    : ViewScreen<NetworkSelectionView>(delegate,
45                                       kWelcomeScreenWidth,
46                                       kWelcomeScreenHeight),
47      is_network_subscribed_(false),
48      continue_pressed_(false),
49      bubble_(NULL) {
50  language_switch_menu_.set_menu_alignment(views::Menu2::ALIGN_TOPLEFT);
51}
52
53NetworkScreen::~NetworkScreen() {
54  connection_timer_.Stop();
55  UnsubscribeNetworkNotification();
56}
57
58////////////////////////////////////////////////////////////////////////////////
59// NetworkScreen, NetworkScreenDelegate implementation:
60
61void NetworkScreen::ClearErrors() {
62  // bubble_ will be set to NULL in callback.
63  if (bubble_)
64    bubble_->Close();
65}
66
67///////////////////////////////////////////////////////////////////////////////
68// views::ButtonListener implementation:
69
70void NetworkScreen::ButtonPressed(views::Button* sender,
71                                  const views::Event& event) {
72  ClearErrors();
73  NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
74  if (network && network->Connected()) {
75    NotifyOnConnection();
76  } else {
77    continue_pressed_ = true;
78    WaitForConnection(network_id_);
79  }
80}
81
82////////////////////////////////////////////////////////////////////////////////
83// NetworkLibrary::NetworkManagerObserver implementation:
84
85void NetworkScreen::OnNetworkManagerChanged(NetworkLibrary* network_lib) {
86  UpdateStatus(network_lib);
87}
88
89///////////////////////////////////////////////////////////////////////////////
90// NetworkScreen, ViewScreen implementation:
91
92void NetworkScreen::CreateView() {
93  language_switch_menu_.InitLanguageMenu();
94  ViewScreen<NetworkSelectionView>::CreateView();
95}
96
97NetworkSelectionView* NetworkScreen::AllocateView() {
98  return new NetworkSelectionView(this);
99}
100
101///////////////////////////////////////////////////////////////////////////////
102// NetworkScreen, views::BubbleDelegate implementation:
103
104void NetworkScreen::OnHelpLinkActivated() {
105  ClearErrors();
106  if (!help_app_.get()) {
107    help_app_ = new HelpAppLauncher(
108        LoginUtils::Get()->GetBackgroundView()->GetNativeWindow());
109  }
110  help_app_->ShowHelpTopic(HelpAppLauncher::HELP_CONNECTIVITY);
111}
112
113////////////////////////////////////////////////////////////////////////////////
114// NetworkScreen, public:
115
116void NetworkScreen::Refresh() {
117  if (CrosLibrary::Get()->EnsureLoaded()) {
118    SubscribeNetworkNotification();
119    OnNetworkManagerChanged(chromeos::CrosLibrary::Get()->GetNetworkLibrary());
120  }
121}
122
123////////////////////////////////////////////////////////////////////////////////
124// NetworkScreen, private:
125
126void NetworkScreen::SubscribeNetworkNotification() {
127  if (!is_network_subscribed_) {
128    is_network_subscribed_ = true;
129    chromeos::CrosLibrary::Get()->GetNetworkLibrary()
130        ->AddNetworkManagerObserver(this);
131  }
132}
133
134void NetworkScreen::UnsubscribeNetworkNotification() {
135  if (is_network_subscribed_) {
136    is_network_subscribed_ = false;
137    chromeos::CrosLibrary::Get()->GetNetworkLibrary()
138        ->RemoveNetworkManagerObserver(this);
139  }
140}
141
142void NetworkScreen::NotifyOnConnection() {
143  // TODO(nkostylev): Check network connectivity.
144  UnsubscribeNetworkNotification();
145  connection_timer_.Stop();
146  delegate()->GetObserver(this)->OnExit(ScreenObserver::NETWORK_CONNECTED);
147}
148
149void NetworkScreen::OnConnectionTimeout() {
150  StopWaitingForConnection(network_id_);
151  NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
152  bool is_connected = network && network->Connected();
153
154  if (!is_connected &&
155      !view()->is_dialog_open() &&
156      !(help_app_.get() && help_app_->is_open())) {
157    // Show error bubble.
158    ClearErrors();
159    views::View* network_control = view()->GetNetworkControlView();
160    bubble_ = MessageBubble::Show(
161        network_control->GetWidget(),
162        network_control->GetScreenBounds(),
163        BubbleBorder::LEFT_TOP,
164        ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
165        UTF16ToWide(l10n_util::GetStringFUTF16(
166            IDS_NETWORK_SELECTION_ERROR,
167            l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME),
168            network_id_)),
169        UTF16ToWide(l10n_util::GetStringUTF16(IDS_LEARN_MORE)),
170        this);
171    network_control->RequestFocus();
172  }
173}
174
175void NetworkScreen::UpdateStatus(NetworkLibrary* network) {
176  if (!view() || !network)
177    return;
178
179  if (network->Connected())
180    ClearErrors();
181
182  string16 network_name = GetCurrentNetworkName(network);
183  if (network->Connected()) {
184    StopWaitingForConnection(network_name);
185  } else if (network->Connecting()) {
186    WaitForConnection(network_name);
187  } else {
188    StopWaitingForConnection(network_id_);
189  }
190}
191
192void NetworkScreen::StopWaitingForConnection(const string16& network_id) {
193  NetworkLibrary* network = CrosLibrary::Get()->GetNetworkLibrary();
194  bool is_connected = network && network->Connected();
195  if (is_connected && continue_pressed_) {
196    NotifyOnConnection();
197    return;
198  }
199
200  continue_pressed_ = false;
201  connection_timer_.Stop();
202
203  network_id_ = network_id;
204  view()->ShowConnectingStatus(false, network_id_);
205  view()->EnableContinue(is_connected);
206}
207
208void NetworkScreen::WaitForConnection(const string16& network_id) {
209  if (network_id_ != network_id || !connection_timer_.IsRunning()) {
210    connection_timer_.Stop();
211    connection_timer_.Start(base::TimeDelta::FromSeconds(kConnectionTimeoutSec),
212                            this,
213                            &NetworkScreen::OnConnectionTimeout);
214  }
215
216  network_id_ = network_id;
217  view()->ShowConnectingStatus(continue_pressed_, network_id_);
218
219  view()->EnableContinue(false);
220}
221
222}  // namespace chromeos
223