network_message_observer.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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/browser_list.h" 12#include "chrome/browser/chromeos/cros/cros_library.h" 13#include "chrome/browser/chromeos/cros/network_library.h" 14#include "chrome/browser/chromeos/notifications/balloon_view_host.h" 15#include "chrome/browser/prefs/pref_service.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/browser.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 24namespace { 25 26// Returns prefs::kShowPlanNotifications in the profile of the last active 27// browser. If there is no active browser, returns true. 28bool 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 39namespace chromeos { 40 41NetworkMessageObserver::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 and a 54 // CellularDataPlanObserver in browser_init.cc 55} 56 57NetworkMessageObserver::~NetworkMessageObserver() { 58 NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary(); 59 netlib->RemoveNetworkManagerObserver(this); 60 netlib->RemoveCellularDataPlanObserver(this); 61 notification_connection_error_.Hide(); 62 notification_low_data_.Hide(); 63 notification_no_data_.Hide(); 64 STLDeleteValues(&cellular_networks_); 65 STLDeleteValues(&wifi_networks_); 66} 67 68// static 69bool NetworkMessageObserver::IsApplicableBackupPlan( 70 const CellularDataPlan* plan, const CellularDataPlan* other_plan) { 71 // By applicable plan, we mean that the other plan has data AND the timeframe 72 // will apply: (unlimited OR used bytes < max bytes) AND 73 // ((start time - 1 sec) <= end time of currently active plan). 74 // In other words, there is data available and there is no gap of more than a 75 // second in time between the old plan and the new plan. 76 bool has_data = other_plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED || 77 other_plan->remaining_data() > 0; 78 bool will_apply = 79 (other_plan->plan_start_time - plan->plan_end_time).InSeconds() <= 1; 80 return has_data && will_apply; 81} 82 83void NetworkMessageObserver::OpenMobileSetupPage(const ListValue* args) { 84 Browser* browser = BrowserList::GetLastActive(); 85 if (browser) 86 browser->OpenMobilePlanTabAndActivate(); 87} 88 89void NetworkMessageObserver::OpenMoreInfoPage(const ListValue* args) { 90 Browser* browser = BrowserList::GetLastActive(); 91 if (!browser) 92 return; 93 chromeos::NetworkLibrary* lib = 94 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 95 const chromeos::CellularNetwork* cellular = lib->cellular_network(); 96 if (!cellular) 97 return; 98 browser->ShowSingletonTab(GURL(cellular->payment_url()), false); 99} 100 101void NetworkMessageObserver::HideDataNotifications() { 102 notification_low_data_.Hide(); 103 notification_no_data_.Hide(); 104} 105 106void NetworkMessageObserver::InitNewPlan(const CellularDataPlan* plan) { 107 HideDataNotifications(); 108 if (plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED) { 109 notification_no_data_.set_title( 110 l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_EXPIRED_TITLE, 111 ASCIIToUTF16(plan->plan_name))); 112 notification_low_data_.set_title( 113 l10n_util::GetStringFUTF16(IDS_NETWORK_NEARING_EXPIRATION_TITLE, 114 ASCIIToUTF16(plan->plan_name))); 115 } else { 116 notification_no_data_.set_title( 117 l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_DATA_TITLE, 118 ASCIIToUTF16(plan->plan_name))); 119 notification_low_data_.set_title( 120 l10n_util::GetStringFUTF16(IDS_NETWORK_LOW_DATA_TITLE, 121 ASCIIToUTF16(plan->plan_name))); 122 } 123} 124 125void NetworkMessageObserver::ShowNoDataNotification( 126 const CellularDataPlan* plan) { 127 notification_low_data_.Hide(); 128 string16 message = 129 plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED ? 130 TimeFormat::TimeRemaining(base::TimeDelta()) : 131 l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_REMAINING_MESSAGE, 132 ASCIIToUTF16("0")); 133 notification_no_data_.Show(message, 134 l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE), 135 NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage), 136 false, false); 137} 138 139void NetworkMessageObserver::ShowLowDataNotification( 140 const CellularDataPlan* plan) { 141 notification_no_data_.Hide(); 142 string16 message = 143 plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED ? 144 plan->GetPlanExpiration() : 145 l10n_util::GetStringFUTF16(IDS_NETWORK_DATA_REMAINING_MESSAGE, 146 UTF8ToUTF16(base::Int64ToString(plan->remaining_mbytes()))); 147 notification_low_data_.Show(message, 148 l10n_util::GetStringUTF16(IDS_NETWORK_MORE_INFO_MESSAGE), 149 NewCallback(this, &NetworkMessageObserver::OpenMoreInfoPage), 150 false, false); 151} 152 153void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* obj) { 154 const WifiNetworkVector& wifi_networks = obj->wifi_networks(); 155 const CellularNetworkVector& cellular_networks = obj->cellular_networks(); 156 157 std::string new_failed_network; 158 // Check to see if we have any newly failed wifi network. 159 for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); 160 it < wifi_networks.end(); it++) { 161 const WifiNetwork* wifi = *it; 162 if (wifi->failed()) { 163 ServicePathWifiMap::iterator iter = 164 wifi_networks_.find(wifi->service_path()); 165 // If the network did not previously exist, then don't do anything. 166 // For example, if the user travels to a location and finds a service 167 // that has previously failed, we don't want to show a notification. 168 if (iter == wifi_networks_.end()) 169 continue; 170 171 const WifiNetwork* wifi_old = iter->second; 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 if (wifi_old->connecting()) { 177 new_failed_network = wifi->name(); 178 // Like above, there should only be one newly failed network. 179 break; 180 } 181 } 182 183 // If we find any network connecting, we hide the error notification. 184 if (wifi->connecting()) { 185 notification_connection_error_.Hide(); 186 } 187 } 188 189 // Refresh stored networks. 190 STLDeleteValues(&wifi_networks_); 191 wifi_networks_.clear(); 192 for (WifiNetworkVector::const_iterator it = wifi_networks.begin(); 193 it < wifi_networks.end(); it++) { 194 const WifiNetwork* wifi = *it; 195 wifi_networks_[wifi->service_path()] = new WifiNetwork(*wifi); 196 } 197 198 STLDeleteValues(&cellular_networks_); 199 cellular_networks_.clear(); 200 for (CellularNetworkVector::const_iterator it = cellular_networks.begin(); 201 it < cellular_networks.end(); it++) { 202 const CellularNetwork* cellular = *it; 203 cellular_networks_[cellular->service_path()] = 204 new CellularNetwork(*cellular); 205 } 206 207 // Show connection error notification if necessary. 208 if (!new_failed_network.empty()) { 209 // Hide if already shown to force show it in case user has closed it. 210 if (notification_connection_error_.visible()) 211 notification_connection_error_.Hide(); 212 notification_connection_error_.Show(l10n_util::GetStringFUTF16( 213 IDS_NETWORK_CONNECTION_ERROR_MESSAGE, 214 ASCIIToUTF16(new_failed_network)), false, false); 215 } 216} 217 218void NetworkMessageObserver::OnCellularDataPlanChanged(NetworkLibrary* obj) { 219 if (!ShouldShowMobilePlanNotifications()) { 220 HideDataNotifications(); 221 return; 222 } 223 224 const CellularNetwork* cellular = obj->cellular_network(); 225 if (!cellular) 226 return; 227 228 // If no plans available, check to see if we need a new plan. 229 if (cellular->GetDataPlans().size() == 0) { 230 HideDataNotifications(); 231 if (cellular->needs_new_plan()) { 232 notification_no_data_.set_title( 233 l10n_util::GetStringFUTF16(IDS_NETWORK_NO_DATA_PLAN_TITLE, 234 UTF8ToUTF16(cellular->service_name()))); 235 notification_no_data_.Show( 236 l10n_util::GetStringFUTF16( 237 IDS_NETWORK_NO_DATA_PLAN_MESSAGE, 238 UTF8ToUTF16(cellular->service_name())), 239 l10n_util::GetStringUTF16(IDS_NETWORK_PURCHASE_MORE_MESSAGE), 240 NewCallback(this, &NetworkMessageObserver::OpenMobileSetupPage), 241 false, false); 242 } 243 return; 244 } 245 246 const CellularDataPlanVector& plans = cellular->GetDataPlans(); 247 CellularDataPlanVector::const_iterator iter = plans.begin(); 248 const CellularDataPlan* current_plan = *iter; 249 250 // If current plan is not the last plan (there is another backup plan), 251 // then we do not show notifications for this plan. 252 // For example, if there is another data plan available when this runs out. 253 for (++iter; iter != plans.end(); ++iter) { 254 if (IsApplicableBackupPlan(current_plan, *iter)) { 255 HideDataNotifications(); 256 return; 257 } 258 } 259 260 // If connected cellular network changed, or data plan is different, then 261 // it's a new network. Then hide all previous notifications. 262 bool new_plan = cellular->service_path() != cellular_service_path_ || 263 current_plan->GetUniqueIdentifier() != cellular_data_plan_unique_id_; 264 265 if (new_plan) { 266 InitNewPlan(current_plan); 267 } 268 269 if (cellular->GetDataLeft() == CellularNetwork::DATA_NONE) { 270 ShowNoDataNotification(current_plan); 271 } else if (cellular->GetDataLeft() == CellularNetwork::DATA_VERY_LOW) { 272 ShowLowDataNotification(current_plan); 273 } else { 274 // Got data, so hide notifications. 275 HideDataNotifications(); 276 } 277 278 cellular_service_path_ = cellular->service_path(); 279 cellular_data_plan_unique_id_ = current_plan->GetUniqueIdentifier(); 280} 281 282} // namespace chromeos 283