• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/callback.h"
8 #include "base/stl_util-inl.h"
9 #include "base/string_number_conversions.h"
10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "chrome/browser/chromeos/cros/network_library.h"
13 #include "chrome/browser/chromeos/notifications/balloon_view_host.h"
14 #include "chrome/browser/prefs/pref_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/common/time_format.h"
20 #include "grit/generated_resources.h"
21 #include "grit/theme_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23 
24 namespace {
25 
26 // Returns prefs::kShowPlanNotifications in the profile of the last active
27 // browser. If there is no active browser, returns true.
ShouldShowMobilePlanNotifications()28 bool ShouldShowMobilePlanNotifications() {
29   Browser* browser = BrowserList::GetLastActive();
30   if (!browser || !browser->profile())
31     return true;
32 
33   PrefService* prefs = browser->profile()->GetPrefs();
34   return prefs->GetBoolean(prefs::kShowPlanNotifications);
35 }
36 
37 }  // namespace
38 
39 namespace chromeos {
40 
NetworkMessageObserver(Profile * profile)41 NetworkMessageObserver::NetworkMessageObserver(Profile* profile)
42     : notification_connection_error_(profile, "network_connection.chromeos",
43           IDR_NOTIFICATION_NETWORK_FAILED,
44           l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE)),
45       notification_low_data_(profile, "network_low_data.chromeos",
46           IDR_NOTIFICATION_BARS_CRITICAL,
47           l10n_util::GetStringUTF16(IDS_NETWORK_LOW_DATA_TITLE)),
48       notification_no_data_(profile, "network_no_data.chromeos",
49           IDR_NOTIFICATION_BARS_EMPTY,
50           l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_DATA_TITLE)) {
51   NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
52   OnNetworkManagerChanged(netlib);
53   // Note that this gets added as a NetworkManagerObserver,
54   // CellularDataPlanObserver, and UserActionObserver in browser_init.cc
55 }
56 
~NetworkMessageObserver()57 NetworkMessageObserver::~NetworkMessageObserver() {
58   NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
59   netlib->RemoveNetworkManagerObserver(this);
60   netlib->RemoveCellularDataPlanObserver(this);
61   netlib->RemoveUserActionObserver(this);
62   notification_connection_error_.Hide();
63   notification_low_data_.Hide();
64   notification_no_data_.Hide();
65 }
66 
67 // static
IsApplicableBackupPlan(const CellularDataPlan * plan,const CellularDataPlan * other_plan)68 bool NetworkMessageObserver::IsApplicableBackupPlan(
69     const CellularDataPlan* plan, const CellularDataPlan* other_plan) {
70   // By applicable plan, we mean that the other plan has data AND the timeframe
71   // will apply: (unlimited OR used bytes < max bytes) AND
72   //   ((start time - 1 sec) <= end time of currently active plan).
73   // In other words, there is data available and there is no gap of more than a
74   // second in time between the old plan and the new plan.
75   bool has_data = other_plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED ||
76       other_plan->remaining_data() > 0;
77   bool will_apply =
78       (other_plan->plan_start_time - plan->plan_end_time).InSeconds() <= 1;
79   return has_data && will_apply;
80 }
81 
OpenMobileSetupPage(const ListValue * args)82 void NetworkMessageObserver::OpenMobileSetupPage(const ListValue* args) {
83   Browser* browser = BrowserList::GetLastActive();
84   if (browser)
85     browser->OpenMobilePlanTabAndActivate();
86 }
87 
OpenMoreInfoPage(const ListValue * args)88 void NetworkMessageObserver::OpenMoreInfoPage(const ListValue* args) {
89   Browser* browser = BrowserList::GetLastActive();
90   if (!browser)
91     return;
92   chromeos::NetworkLibrary* lib =
93       chromeos::CrosLibrary::Get()->GetNetworkLibrary();
94   const chromeos::CellularNetwork* cellular = lib->cellular_network();
95   if (!cellular)
96     return;
97   browser->ShowSingletonTab(GURL(cellular->payment_url()));
98 }
99 
InitNewPlan(const CellularDataPlan * plan)100 void NetworkMessageObserver::InitNewPlan(const CellularDataPlan* plan) {
101   notification_low_data_.Hide();
102   notification_no_data_.Hide();
103   if (plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED) {
104     notification_no_data_.set_title(
105         l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_EXPIRED_TITLE,
106                                    ASCIIToUTF16(plan->plan_name)));
107     notification_low_data_.set_title(
108         l10n_util::GetStringFUTF16(IDS_NETWORK_NEARING_EXPIRATION_TITLE,
109                                    ASCIIToUTF16(plan->plan_name)));
110   } else {
111     notification_no_data_.set_title(
112         l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_DATA_TITLE,
113                                    ASCIIToUTF16(plan->plan_name)));
114     notification_low_data_.set_title(
115         l10n_util::GetStringFUTF16(IDS_NETWORK_LOW_DATA_TITLE,
116                                    ASCIIToUTF16(plan->plan_name)));
117   }
118 }
119 
ShowNeedsPlanNotification(const CellularNetwork * cellular)120 void NetworkMessageObserver::ShowNeedsPlanNotification(
121     const CellularNetwork* cellular) {
122   notification_no_data_.set_title(
123       l10n_util::GetStringFUTF16(IDS_NETWORK_NO_DATA_PLAN_TITLE,
124                                  UTF8ToUTF16(cellular->name())));
125   notification_no_data_.Show(
126       l10n_util::GetStringFUTF16(
127           IDS_NETWORK_NO_DATA_PLAN_MESSAGE,
128           UTF8ToUTF16(cellular->name())),
129       l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE),
130       NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage),
131       false, false);
132 }
133 
ShowNoDataNotification(CellularDataPlanType plan_type)134 void NetworkMessageObserver::ShowNoDataNotification(
135     CellularDataPlanType plan_type) {
136   notification_low_data_.Hide();  // Hide previous low data notification.
137   string16 message = plan_type == CELLULAR_DATA_PLAN_UNLIMITED ?
138       TimeFormat::TimeRemaining(base::TimeDelta()) :
139       l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_REMAINING_MESSAGE,
140                                  ASCIIToUTF16("0"));
141   notification_no_data_.Show(message,
142       l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE),
143       NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage),
144       false, false);
145 }
146 
ShowLowDataNotification(const CellularDataPlan * plan)147 void NetworkMessageObserver::ShowLowDataNotification(
148     const CellularDataPlan* plan) {
149   string16 message;
150   if (plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED) {
151     message = plan->GetPlanExpiration();
152   } else {
153     int64 remaining_mbytes = plan->remaining_data() / (1024 * 1024);
154     message = l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_REMAINING_MESSAGE,
155         UTF8ToUTF16(base::Int64ToString(remaining_mbytes)));
156   }
157   notification_low_data_.Show(message,
158       l10n_util::GetStringUTF16(IDS_NETWORK_MORE_INFO_MESSAGE),
159       NewCallback(this, &NetworkMessageObserver::OpenMoreInfoPage),
160       false, false);
161 }
162 
CheckNetworkFailed(const Network * network)163 bool NetworkMessageObserver::CheckNetworkFailed(const Network* network) {
164   if (network->failed()) {
165     NetworkStateMap::iterator iter =
166         network_states_.find(network->service_path());
167     // If the network did not previously exist, then don't do anything.
168     // For example, if the user travels to a location and finds a service
169     // that has previously failed, we don't want to show a notification.
170     if (iter == network_states_.end())
171       return false;
172     // If network connection failed, display a notification.
173     // We only do this if we were trying to make a new connection.
174     // So if a previously connected network got disconnected for any reason,
175     // we don't display notification.
176     ConnectionState prev_state = iter->second;
177     if (Network::IsConnectingState(prev_state))
178       return true;
179   }
180   return false;
181 }
182 
OnNetworkManagerChanged(NetworkLibrary * cros)183 void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* cros) {
184   const Network* new_failed_network = NULL;
185   // Check to see if we have any newly failed networks.
186   for (WifiNetworkVector::const_iterator it = cros->wifi_networks().begin();
187        it != cros->wifi_networks().end(); it++) {
188     const WifiNetwork* net = *it;
189     if (CheckNetworkFailed(net)) {
190       new_failed_network = net;
191       break;  // There should only be one failed network.
192     }
193   }
194 
195   if (!new_failed_network) {
196     for (CellularNetworkVector::const_iterator it =
197              cros->cellular_networks().begin();
198          it != cros->cellular_networks().end(); it++) {
199       const CellularNetwork* net = *it;
200       if (CheckNetworkFailed(net)) {
201         new_failed_network = net;
202         break;  // There should only be one failed network.
203       }
204     }
205   }
206 
207   if (!new_failed_network) {
208     for (VirtualNetworkVector::const_iterator it =
209              cros->virtual_networks().begin();
210          it != cros->virtual_networks().end(); it++) {
211       const VirtualNetwork* net = *it;
212       if (CheckNetworkFailed(net)) {
213         new_failed_network = net;
214         break;  // There should only be one failed network.
215       }
216     }
217   }
218 
219   network_states_.clear();
220   for (WifiNetworkVector::const_iterator it = cros->wifi_networks().begin();
221        it != cros->wifi_networks().end(); it++)
222     network_states_[(*it)->service_path()] = (*it)->state();
223   for (CellularNetworkVector::const_iterator it =
224            cros->cellular_networks().begin();
225        it != cros->cellular_networks().end(); it++)
226     network_states_[(*it)->service_path()] = (*it)->state();
227   for (VirtualNetworkVector::const_iterator it =
228            cros->virtual_networks().begin();
229        it != cros->virtual_networks().end(); it++)
230     network_states_[(*it)->service_path()] = (*it)->state();
231 
232   // Show connection error notification if necessary.
233   if (new_failed_network) {
234     // Hide if already shown to force show it in case user has closed it.
235     if (notification_connection_error_.visible())
236       notification_connection_error_.Hide();
237     notification_connection_error_.Show(l10n_util::GetStringFUTF16(
238         IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
239         UTF8ToUTF16(new_failed_network->name())), false, false);
240   }
241 }
242 
OnCellularDataPlanChanged(NetworkLibrary * cros)243 void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* cros) {
244   if (!ShouldShowMobilePlanNotifications())
245     return;
246   const CellularNetwork* cellular = cros->cellular_network();
247   if (!cellular || !cellular->SupportsDataPlan())
248     return;
249 
250   const CellularDataPlanVector* plans =
251       cros->GetDataPlans(cellular->service_path());
252   // If no plans available, check to see if we need a new plan.
253   if (!plans || plans->empty()) {
254     // If previously, we had low data, we know that a plan was near expiring.
255     // In that case, because the plan disappeared, we assume that it expired.
256     if (cellular_data_left_ == CellularNetwork::DATA_LOW) {
257       ShowNoDataNotification(cellular_data_plan_type_);
258     } else if (cellular->needs_new_plan()) {
259       ShowNeedsPlanNotification(cellular);
260     }
261     SaveLastCellularInfo(cellular, NULL);
262     return;
263   }
264 
265   CellularDataPlanVector::const_iterator iter = plans->begin();
266   const CellularDataPlan* current_plan = *iter;
267 
268   // If current plan is not the last plan (there is another backup plan),
269   // then we do not show notifications for this plan.
270   // For example, if there is another data plan available when this runs out.
271   for (++iter; iter != plans->end(); ++iter) {
272     if (IsApplicableBackupPlan(current_plan, *iter)) {
273       SaveLastCellularInfo(cellular, current_plan);
274       return;
275     }
276   }
277 
278   // If connected cellular network changed, or data plan is different, then
279   // it's a new network. Then hide all previous notifications.
280   bool new_plan = cellular->service_path() != cellular_service_path_ ||
281       current_plan->GetUniqueIdentifier() != cellular_data_plan_unique_id_;
282 
283   if (new_plan) {
284     InitNewPlan(current_plan);
285   }
286 
287   if (cellular->data_left() == CellularNetwork::DATA_NONE) {
288     ShowNoDataNotification(current_plan->plan_type);
289   } else if (cellular->data_left() == CellularNetwork::DATA_VERY_LOW) {
290     // Only show low data notification if we transition to very low data
291     // and we are on the same plan. This is so that users don't get a
292     // notification whenever they connect to a low data 3g network.
293     if (!new_plan && (cellular_data_left_ != CellularNetwork::DATA_VERY_LOW))
294       ShowLowDataNotification(current_plan);
295   }
296 
297   SaveLastCellularInfo(cellular, current_plan);
298 }
299 
OnConnectionInitiated(NetworkLibrary * cros,const Network * network)300 void NetworkMessageObserver::OnConnectionInitiated(NetworkLibrary* cros,
301                                                    const Network* network) {
302   // If user initiated any network connection, we hide the error notification.
303   notification_connection_error_.Hide();
304 }
305 
SaveLastCellularInfo(const CellularNetwork * cellular,const CellularDataPlan * plan)306 void NetworkMessageObserver::SaveLastCellularInfo(
307     const CellularNetwork* cellular, const CellularDataPlan* plan) {
308   DCHECK(cellular);
309   cellular_service_path_ = cellular->service_path();
310   cellular_data_left_ = cellular->data_left();
311   if (plan) {
312     cellular_data_plan_unique_id_ = plan->GetUniqueIdentifier();
313     cellular_data_plan_type_ = plan->plan_type;
314   } else {
315     cellular_data_plan_unique_id_ = std::string();
316     cellular_data_plan_type_ = CELLULAR_DATA_PLAN_UNKNOWN;
317   }
318 }
319 
320 }  // namespace chromeos
321