network_message_observer.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
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/network_message_observer.h"
6
7#include "app/l10n_util.h"
8#include "base/callback.h"
9#include "base/stl_util-inl.h"
10#include "base/string_number_conversions.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/browser_list.h"
13#include "chrome/browser/browser_window.h"
14#include "chrome/browser/chromeos/cros/cros_library.h"
15#include "chrome/browser/chromeos/cros/network_library.h"
16#include "chrome/browser/chromeos/notifications/balloon_view_host.h"
17#include "chrome/browser/chromeos/options/network_config_view.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/views/window.h"
20#include "grit/generated_resources.h"
21#include "grit/theme_resources.h"
22#include "views/window/dialog_delegate.h"
23#include "views/window/window.h"
24
25namespace chromeos {
26
27NetworkMessageObserver::NetworkMessageObserver(Profile* profile)
28    : initialized_(false),
29      notification_connection_error_(profile, "network_connection.chromeos",
30          IDR_NOTIFICATION_NETWORK_FAILED,
31          l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE)),
32      notification_low_data_(profile, "network_low_data.chromeos",
33          IDR_NOTIFICATION_BARS_CRITICAL,
34          l10n_util::GetStringUTF16(IDS_NETWORK_LOW_DATA_TITLE)),
35      notification_no_data_(profile, "network_no_data.chromeos",
36          IDR_NOTIFICATION_BARS_EMPTY,
37          l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_DATA_TITLE)) {
38  NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
39  OnNetworkManagerChanged(netlib);
40  // Note that this gets added as a NetworkManagerObserver and a
41  // CellularDataPlanObserver in browser_init.cc
42  initialized_ = true;
43}
44
45NetworkMessageObserver::~NetworkMessageObserver() {
46  NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
47  netlib->RemoveNetworkManagerObserver(this);
48  netlib->RemoveCellularDataPlanObserver(this);
49  notification_connection_error_.Hide();
50  notification_low_data_.Hide();
51  notification_no_data_.Hide();
52  STLDeleteValues(&cellular_networks_);
53  STLDeleteValues(&wifi_networks_);
54}
55
56void NetworkMessageObserver::CreateModalPopup(views::WindowDelegate* view) {
57  Browser* browser = BrowserList::GetLastActive();
58  if (browser && browser->type() != Browser::TYPE_NORMAL) {
59    browser = BrowserList::FindBrowserWithType(browser->profile(),
60                                               Browser::TYPE_NORMAL,
61                                               true);
62  }
63  DCHECK(browser);
64  views::Window* window = browser::CreateViewsWindow(
65      browser->window()->GetNativeHandle(), gfx::Rect(), view);
66  window->SetIsAlwaysOnTop(true);
67  window->Show();
68}
69
70void NetworkMessageObserver::OpenMobileSetupPage(const ListValue* args) {
71  Browser* browser = BrowserList::GetLastActive();
72  if (browser)
73    browser->OpenMobilePlanTabAndActivate();
74}
75
76void NetworkMessageObserver::OpenMoreInfoPage(const ListValue* args) {
77  Browser* browser = BrowserList::GetLastActive();
78  if (!browser)
79    return;
80  chromeos::NetworkLibrary* lib =
81      chromeos::CrosLibrary::Get()->GetNetworkLibrary();
82  chromeos::CellularNetwork* cellular = lib->cellular_network();
83  if (!cellular)
84    return;
85  browser->ShowSingletonTab(GURL(cellular->payment_url()), false);
86}
87
88void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* obj) {
89  const WifiNetworkVector& wifi_networks = obj->wifi_networks();
90  const CellularNetworkVector& cellular_networks = obj->cellular_networks();
91
92  NetworkConfigView* view = NULL;
93  std::string new_failed_network;
94  // Check to see if we have any newly failed wifi network.
95  for (WifiNetworkVector::const_iterator it = wifi_networks.begin();
96       it < wifi_networks.end(); it++) {
97    const WifiNetwork* wifi = *it;
98    if (wifi->failed()) {
99      ServicePathWifiMap::iterator iter =
100          wifi_networks_.find(wifi->service_path());
101      // If the network did not previously exist, then don't do anything.
102      // For example, if the user travels to a location and finds a service
103      // that has previously failed, we don't want to show a notification.
104      if (iter == wifi_networks_.end())
105        continue;
106
107      const WifiNetwork* wifi_old = iter->second;
108      // If this network was in a failed state previously, then it's not new.
109      if (wifi_old->failed())
110        continue;
111
112      // Display login box again for bad_passphrase and bad_wepkey errors.
113      if (wifi->error() == ERROR_BAD_PASSPHRASE ||
114          wifi->error() == ERROR_BAD_WEPKEY) {
115        // The NetworkConfigView will show the appropriate error message.
116        view = new NetworkConfigView(wifi, true);
117        // There should only be one wifi network that failed to connect.
118        // If for some reason, we have more than one failure,
119        // we only display the first one. So we break here.
120        break;
121      }
122
123      // If network connection failed, display a notification.
124      // We only do this if we were trying to make a new connection.
125      // So if a previously connected network got disconnected for any reason,
126      // we don't display notification.
127      if (wifi_old->connecting()) {
128        new_failed_network = wifi->name();
129        // Like above, there should only be one newly failed network.
130        break;
131      }
132    }
133
134    // If we find any network connecting, we hide the error notification.
135    if (wifi->connecting()) {
136      notification_connection_error_.Hide();
137    }
138  }
139
140  // Refresh stored networks.
141  STLDeleteValues(&wifi_networks_);
142  wifi_networks_.clear();
143  for (WifiNetworkVector::const_iterator it = wifi_networks.begin();
144       it < wifi_networks.end(); it++) {
145    const WifiNetwork* wifi = *it;
146    wifi_networks_[wifi->service_path()] = new WifiNetwork(*wifi);
147  }
148
149  STLDeleteValues(&cellular_networks_);
150  cellular_networks_.clear();
151  for (CellularNetworkVector::const_iterator it = cellular_networks.begin();
152       it < cellular_networks.end(); it++) {
153    const CellularNetwork* cellular = *it;
154    cellular_networks_[cellular->service_path()] =
155        new CellularNetwork(*cellular);
156  }
157
158  // Show connection error notification if necessary.
159  if (!new_failed_network.empty()) {
160    // Hide if already shown to force show it in case user has closed it.
161    if (notification_connection_error_.visible())
162      notification_connection_error_.Hide();
163    notification_connection_error_.Show(l10n_util::GetStringFUTF16(
164        IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
165        ASCIIToUTF16(new_failed_network)), false, false);
166  }
167
168  // Show login box if necessary.
169  if (view && initialized_)
170    CreateModalPopup(view);
171}
172
173void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* obj) {
174  const CellularNetwork* cellular = obj->cellular_network();
175  if (!cellular)
176    return;
177  // Active plan is the first one in the list. Use empty one if none found.
178  const CellularDataPlanVector& plans = cellular->GetDataPlans();
179  CellularDataPlan plan = plans.empty() ? CellularDataPlan() : plans[0];
180  // If connected cellular network changed, or data plan is different, then
181  // it's a new network. Then hide all previous notifications.
182  bool new_plan = false;
183  if (cellular->service_path() != cellular_service_path_) {
184    cellular_service_path_ = cellular->service_path();
185    new_plan = true;
186  } else if (plan.plan_name != cellular_data_plan_.plan_name ||
187      plan.plan_type != cellular_data_plan_.plan_type) {
188    new_plan = true;
189  }
190
191  cellular_data_plan_ = plan;
192
193  if (new_plan) {
194    notification_low_data_.Hide();
195    notification_no_data_.Hide();
196    if (plans.empty() && cellular->needs_new_plan()) {
197      notification_no_data_.set_title(
198          l10n_util::GetStringFUTF16(IDS_NETWORK_NO_DATA_PLAN_TITLE,
199                                     UTF8ToUTF16(cellular->service_name())));
200      notification_no_data_.Show(
201          l10n_util::GetStringFUTF16(
202              IDS_NETWORK_NO_DATA_PLAN_MESSAGE,
203              UTF8ToUTF16(cellular->service_name())),
204          l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE),
205          NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage),
206          false, false);
207      return;
208    } else if (plan.plan_type == CELLULAR_DATA_PLAN_UNLIMITED) {
209      notification_no_data_.set_title(
210          l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_EXPIRED_TITLE,
211                                     ASCIIToUTF16(plan.plan_name)));
212      notification_low_data_.set_title(
213          l10n_util::GetStringFUTF16(IDS_NETWORK_NEARING_EXPIRATION_TITLE,
214                                     ASCIIToUTF16(plan.plan_name)));
215    } else {
216      notification_no_data_.set_title(
217          l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_DATA_TITLE,
218                                     ASCIIToUTF16(plan.plan_name)));
219      notification_low_data_.set_title(
220          l10n_util::GetStringFUTF16(IDS_NETWORK_LOW_DATA_TITLE,
221                                     ASCIIToUTF16(plan.plan_name)));
222    }
223  }
224
225  if (plan.plan_type == CELLULAR_DATA_PLAN_UNKNOWN)
226    return;
227
228  if (cellular->data_left() == CellularNetwork::DATA_NONE) {
229    notification_low_data_.Hide();
230    int message = plan.plan_type == CELLULAR_DATA_PLAN_UNLIMITED ?
231        IDS_NETWORK_MINUTES_REMAINING_MESSAGE :
232        IDS_NETWORK_DATA_REMAINING_MESSAGE;
233    notification_no_data_.Show(l10n_util::GetStringFUTF16(
234        message, ASCIIToUTF16("0")),
235        l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE),
236        NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage),
237        false, false);
238  } else if (cellular->data_left() == CellularNetwork::DATA_VERY_LOW) {
239    notification_no_data_.Hide();
240    int message = plan.plan_type == CELLULAR_DATA_PLAN_UNLIMITED ?
241        IDS_NETWORK_MINUTES_REMAINING_MESSAGE :
242        IDS_NETWORK_DATA_REMAINING_MESSAGE;
243    int64 remaining = plan.plan_type ==
244        CELLULAR_DATA_PLAN_UNLIMITED ? plan.remaining_minutes() :
245                                       plan.remaining_mbytes();
246    notification_low_data_.Show(l10n_util::GetStringFUTF16(
247        message, UTF8ToUTF16(base::Int64ToString(remaining))),
248        l10n_util::GetStringUTF16(IDS_NETWORK_MORE_INFO_MESSAGE),
249        NewCallback(this, &NetworkMessageObserver::OpenMoreInfoPage),
250        false, false);
251  } else {
252    // Got data, so hide notifications.
253    notification_low_data_.Hide();
254    notification_no_data_.Hide();
255  }
256}
257
258}  // namespace chromeos
259