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