diff options
author | nkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-05 18:23:09 +0000 |
---|---|---|
committer | nkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-05 18:23:09 +0000 |
commit | d6ae95070a36fa548f07f919b99f6d18501c20e5 (patch) | |
tree | 0ac04df16e3d56b9c1c4a9c0b972e1b5f2a99451 /chrome | |
parent | 2273b6e647b5a52a721d1a6d7157eaf25f192ebb (diff) | |
download | chromium_src-d6ae95070a36fa548f07f919b99f6d18501c20e5.zip chromium_src-d6ae95070a36fa548f07f919b99f6d18501c20e5.tar.gz chromium_src-d6ae95070a36fa548f07f919b99f6d18501c20e5.tar.bz2 |
[cros] Add support for carrier deals.
- Expose carrierID (homeProvider).
- Check for deal validity (locale, date).
- Add deal notification text to 3G promo bubble.
- Use top up URL from carrier deal as "View Account" link in network menu/promo.
BUG=chromium-os:14575, chromium-os:14671
TEST=Manual. Used manifest with deal for local provider, checked that UI elements are customized.
Review URL: http://codereview.chromium.org/6929011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84270 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
18 files changed, 560 insertions, 79 deletions
diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h index 0223615..aad9deb 100644 --- a/chrome/browser/chromeos/cros/mock_network_library.h +++ b/chrome/browser/chromeos/cros/mock_network_library.h @@ -118,6 +118,7 @@ class MockNetworkLibrary : public NetworkLibrary { MOCK_METHOD1(DisconnectFromNetwork, void(const Network*)); MOCK_METHOD1(ForgetWifiNetwork, void(const std::string&)); + MOCK_CONST_METHOD0(GetCellularHomeCarrierId, std::string(void)); MOCK_CONST_METHOD0(ethernet_available, bool(void)); MOCK_CONST_METHOD0(wifi_available, bool(void)); diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc index d53e0d0..9019e46 100644 --- a/chrome/browser/chromeos/cros/network_library.cc +++ b/chrome/browser/chromeos/cros/network_library.cc @@ -12,6 +12,7 @@ #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/string_util.h" +#include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/chromeos/cros/cros_library.h" @@ -94,6 +95,9 @@ const int kRecentPlanPaymentHours = 6; // If cellular device doesn't have SIM card, then retries are never used. const int kDefaultSimUnlockRetriesCount = 999; +// Format of the Carrier ID: <carrier name> (<carrier country>). +const char* kCarrierIdFormat = "%s (%s)"; + // Type of a pending SIM operation. enum SimOperationType { SIM_OPERATION_NONE = 0, @@ -131,6 +135,7 @@ const char* kNetworkTechnologyProperty = "Cellular.NetworkTechnology"; const char* kRoamingStateProperty = "Cellular.RoamingState"; const char* kOperatorNameProperty = "Cellular.OperatorName"; const char* kOperatorCodeProperty = "Cellular.OperatorCode"; +const char* kServingOperatorProperty = "Cellular.ServingOperator"; const char* kPaymentURLProperty = "Cellular.OlpUrl"; const char* kUsageURLProperty = "Cellular.UsageUrl"; const char* kCellularApnProperty = "Cellular.APN"; @@ -169,6 +174,11 @@ const char* kNetworkIdProperty = "network_id"; const char* kUsernameProperty = "username"; const char* kPasswordProperty = "password"; +// Operator info property names. +const char* kOperatorNameKey = "name"; +const char* kOperatorCodeKey = "code"; +const char* kOperatorCountryKey = "country"; + // Flimflam device info property names. const char* kScanningProperty = "Scanning"; const char* kCarrierProperty = "Cellular.Carrier"; @@ -485,6 +495,7 @@ enum PropertyIndex { PROPERTY_INDEX_SELECTED_NETWORK, PROPERTY_INDEX_SERVICES, PROPERTY_INDEX_SERVICE_WATCH_LIST, + PROPERTY_INDEX_SERVING_OPERATOR, PROPERTY_INDEX_SIGNAL_STRENGTH, PROPERTY_INDEX_SIM_LOCK, PROPERTY_INDEX_STATE, @@ -570,6 +581,7 @@ StringToEnum<PropertyIndex>::Pair property_index_table[] = { { kSelectedNetworkProperty, PROPERTY_INDEX_SELECTED_NETWORK }, { kServiceWatchListProperty, PROPERTY_INDEX_SERVICE_WATCH_LIST }, { kServicesProperty, PROPERTY_INDEX_SERVICES }, + { kServingOperatorProperty, PROPERTY_INDEX_SERVING_OPERATOR }, { kSignalStrengthProperty, PROPERTY_INDEX_SIGNAL_STRENGTH }, { kSIMLockStatusProperty, PROPERTY_INDEX_SIM_LOCK }, { kStateProperty, PROPERTY_INDEX_STATE }, @@ -876,8 +888,33 @@ bool NetworkDevice::ParseValue(int index, const Value* value) { &found_cellular_networks_); } break; - case PROPERTY_INDEX_HOME_PROVIDER: - return value->GetAsString(&home_provider_); + case PROPERTY_INDEX_HOME_PROVIDER: { + if (value->IsType(Value::TYPE_DICTIONARY)) { + const DictionaryValue *dict = + static_cast<const DictionaryValue*>(value); + home_provider_code_.clear(); + home_provider_country_.clear(); + home_provider_name_.clear(); + dict->GetStringWithoutPathExpansion(kOperatorCodeKey, + &home_provider_code_); + dict->GetStringWithoutPathExpansion(kOperatorCountryKey, + &home_provider_country_); + dict->GetStringWithoutPathExpansion(kOperatorNameKey, + &home_provider_name_); + if (!home_provider_name_.empty() && !home_provider_country_.empty()) { + home_provider_id_ = base::StringPrintf( + kCarrierIdFormat, + home_provider_name_.c_str(), + home_provider_country_.c_str()); + } else { + home_provider_id_ = home_provider_code_; + LOG(WARNING) << "Carrier ID not defined, using code instead: " + << home_provider_id_; + } + return true; + } + break; + } case PROPERTY_INDEX_MEID: return value->GetAsString(&MEID_); case PROPERTY_INDEX_IMEI: @@ -1522,6 +1559,23 @@ bool CellularNetwork::ParseValue(int index, const Value* value) { return value->GetAsString(&operator_name_); case PROPERTY_INDEX_OPERATOR_CODE: return value->GetAsString(&operator_code_); + case PROPERTY_INDEX_SERVING_OPERATOR: { + if (value->IsType(Value::TYPE_DICTIONARY)) { + const DictionaryValue *dict = + static_cast<const DictionaryValue*>(value); + operator_code_.clear(); + operator_country_.clear(); + operator_name_.clear(); + dict->GetStringWithoutPathExpansion(kOperatorNameKey, + &operator_name_); + dict->GetStringWithoutPathExpansion(kOperatorCodeKey, + &operator_code_); + dict->GetStringWithoutPathExpansion(kOperatorCountryKey, + &operator_country_); + return true; + } + break; + } case PROPERTY_INDEX_PAYMENT_URL: return value->GetAsString(&payment_url_); case PROPERTY_INDEX_USAGE_URL: @@ -2779,6 +2833,16 @@ class NetworkLibraryImpl : public NetworkLibrary { NotifyNetworkManagerChanged(true); // Forced update. } + virtual std::string GetCellularHomeCarrierId() const { + std::string carrier_id; + const NetworkDevice* cellular = FindCellularDevice(); + if (cellular) { + return cellular->home_provider_id(); + + } + return carrier_id; + } + virtual bool ethernet_available() const { return available_devices_ & (1 << TYPE_ETHERNET); } @@ -4311,6 +4375,7 @@ class NetworkLibraryStubImpl : public NetworkLibrary { virtual bool HasRecentCellularPlanPayment() { return false; } virtual void DisconnectFromNetwork(const Network* network) {} virtual void ForgetWifiNetwork(const std::string& service_path) {} + virtual std::string GetCellularHomeCarrierId() const { return std::string(); } virtual bool ethernet_available() const { return true; } virtual bool wifi_available() const { return false; } virtual bool cellular_available() const { return false; } diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h index 3606dad..e02890c 100644 --- a/chrome/browser/chromeos/cros/network_library.h +++ b/chrome/browser/chromeos/cros/network_library.h @@ -213,6 +213,12 @@ class NetworkDevice { const std::string& last_update() const { return last_update_; } const unsigned int prl_version() const { return PRL_version_; } const std::string& home_provider() const { return home_provider_; } + const std::string& home_provider_code() const { return home_provider_code_; } + const std::string& home_provider_country() const { + return home_provider_country_; + } + const std::string& home_provider_id() const { return home_provider_id_; } + const std::string& home_provider_name() const { return home_provider_name_; } const std::string& selected_cellular_network() const { return selected_cellular_network_; } @@ -233,6 +239,10 @@ class NetworkDevice { // Cellular specific device info. std::string carrier_; std::string home_provider_; + std::string home_provider_code_; + std::string home_provider_country_; + std::string home_provider_id_; + std::string home_provider_name_; std::string MEID_; std::string IMEI_; std::string IMSI_; @@ -580,6 +590,7 @@ class CellularNetwork : public WirelessNetwork { } const std::string& operator_name() const { return operator_name_; } const std::string& operator_code() const { return operator_code_; } + const std::string& operator_country() const { return operator_country_; } const std::string& payment_url() const { return payment_url_; } const std::string& usage_url() const { return usage_url_; } DataLeft data_left() const { return data_left_; } @@ -616,6 +627,7 @@ class CellularNetwork : public WirelessNetwork { // Carrier Info std::string operator_name_; std::string operator_code_; + std::string operator_country_; std::string payment_url_; std::string usage_url_; // Cached values @@ -1128,6 +1140,10 @@ class NetworkLibrary { // Forget the wifi network corresponding to service_path. virtual void ForgetWifiNetwork(const std::string& service_path) = 0; + // Returns home carrier ID if available, otherwise empty string is returned. + // Carrier ID format: <carrier name> (country). Ex.: "Verizon (us)". + virtual std::string GetCellularHomeCarrierId() const = 0; + virtual bool ethernet_available() const = 0; virtual bool wifi_available() const = 0; virtual bool cellular_available() const = 0; diff --git a/chrome/browser/chromeos/customization_document.cc b/chrome/browser/chromeos/customization_document.cc index 35938c8..33e40d2 100644 --- a/chrome/browser/chromeos/customization_document.cc +++ b/chrome/browser/chromeos/customization_document.cc @@ -10,9 +10,12 @@ #include "base/logging.h" #include "base/string_tokenizer.h" #include "base/string_util.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/system_access.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile_manager.h" @@ -41,6 +44,15 @@ const char kAcceptedManifestVersion[] = "1.0"; const char kHwid[] = "hwid"; +// Carrier deals attributes. +const char kCarrierDealsAttr[] = "carrier_deals"; +const char kDealLocaleAttr[] = "deal_locale"; +const char kTopUpURLAttr[] = "top_up_url"; +const char kNotificationCountAttr[] = "notification_count"; +const char kDealExpireDateAttr[] = "expire_date"; +const char kLocalizedContentAttr[] = "localized_content"; +const char kNotificationTextAttr[] = "notification_text"; + // Path to OEM partner startup customization manifest. const char kStartupCustomizationManifestPath[] = "/opt/oem/etc/startup_manifest.json"; @@ -202,12 +214,45 @@ std::string StartupCustomizationDocument::GetEULAPage( // ServicesCustomizationDocument implementation. ------------------------------- +ServicesCustomizationDocument::CarrierDeal::CarrierDeal( + DictionaryValue* deal_dict) + : notification_count(0), + localized_strings(NULL) { + deal_dict->GetString(kDealLocaleAttr, &deal_locale); + deal_dict->GetString(kTopUpURLAttr, &top_up_url); + deal_dict->GetInteger(kNotificationCountAttr, ¬ification_count); + std::string date_string; + if (deal_dict->GetString(kDealExpireDateAttr, &date_string)) { + if (!base::Time::FromString(ASCIIToWide(date_string).c_str(), &expire_date)) + LOG(ERROR) << "Error parsing deal_expire_date: " << date_string; + } + deal_dict->GetDictionary(kLocalizedContentAttr, &localized_strings); +} + +std::string ServicesCustomizationDocument::CarrierDeal::GetLocalizedString( + const std::string& locale, const std::string& id) const { + std::string result; + if (localized_strings) { + DictionaryValue* locale_dict = NULL; + if (localized_strings->GetDictionary(locale, &locale_dict) && + locale_dict->GetString(id, &result)) { + return result; + } else if (localized_strings->GetDictionary(kDefaultAttr, &locale_dict) && + locale_dict->GetString(id, &result)) { + return result; + } + } + return result; +} + ServicesCustomizationDocument::ServicesCustomizationDocument() - : url_(kServicesCustomizationManifestUrl) { + : url_(kServicesCustomizationManifestUrl), + initial_locale_(WizardController::GetInitialLocale()) { } ServicesCustomizationDocument::ServicesCustomizationDocument( - const std::string& manifest) { + const std::string& manifest, const std::string& initial_locale) + : initial_locale_(initial_locale) { LoadManifestFromString(manifest); } @@ -310,4 +355,45 @@ std::string ServicesCustomizationDocument::GetSupportPage( locale, kAppContentAttr, kSupportPageAttr); } +const ServicesCustomizationDocument::CarrierDeal* +ServicesCustomizationDocument::GetCarrierDeal(const std::string& carrier_id, + bool check_restrictions) const { + CarrierDeals::const_iterator iter = carrier_deals_.find(carrier_id); + if (iter != carrier_deals_.end()) { + CarrierDeal* deal = iter->second; + if (check_restrictions) { + // Deal locale has to match initial_locale (= launch country). + if (initial_locale_ != deal->deal_locale) + return NULL; + // Make sure that deal is still active, + // i.e. if deal expire date is defined, check it. + if (!deal->expire_date.is_null() && + deal->expire_date <= base::Time::Now()) { + return NULL; + } + } + return deal; + } else { + return NULL; + } +} + +bool ServicesCustomizationDocument::LoadManifestFromString( + const std::string& manifest) { + if (!CustomizationDocument::LoadManifestFromString(manifest)) + return false; + + DictionaryValue* carriers = NULL; + if (root_.get() && root_->GetDictionary(kCarrierDealsAttr, &carriers)) { + for (DictionaryValue::key_iterator iter = carriers->begin_keys(); + iter != carriers->end_keys(); ++iter) { + DictionaryValue* carrier_deal = NULL; + if (carriers->GetDictionary(*iter, &carrier_deal)) { + carrier_deals_[*iter] = new CarrierDeal(carrier_deal); + } + } + } + return true; +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/customization_document.h b/chrome/browser/chromeos/customization_document.h index 66d711a..f673266 100644 --- a/chrome/browser/chromeos/customization_document.h +++ b/chrome/browser/chromeos/customization_document.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_CUSTOMIZATION_DOCUMENT_H_ #pragma once +#include <map> #include <string> #include "base/gtest_prod_util.h" @@ -21,6 +22,10 @@ class FilePath; class ListValue; class PrefService; +namespace base { + class Time; +} + namespace chromeos { class SystemAccess; @@ -99,6 +104,26 @@ class StartupCustomizationDocument : public CustomizationDocument { class ServicesCustomizationDocument : public CustomizationDocument, private URLFetcher::Delegate { public: + // OEM specific carrier deal. + struct CarrierDeal { + explicit CarrierDeal(DictionaryValue* deal_dict); + + // Returns string with the specified |locale| and |id|. + // If there's no version for |locale|, default one is returned. + // If there's no string with specified |id|, empty string is returned. + std::string GetLocalizedString(const std::string& locale, + const std::string& id) const; + + std::string deal_locale; + std::string top_up_url; + int notification_count; + base::Time expire_date; + DictionaryValue* localized_strings; + }; + + // Carrier ID (ex. "Verizon (us)") mapping to carrier deals. + typedef std::map<std::string, CarrierDeal*> CarrierDeals; + static ServicesCustomizationDocument* GetInstance(); // Registers preferences. @@ -118,16 +143,29 @@ class ServicesCustomizationDocument : public CustomizationDocument, std::string GetInitialStartPage(const std::string& locale) const; std::string GetSupportPage(const std::string& locale) const; + // Returns carrier deal by specified |carrier_id|. + // Also checks deal restrictions, such as deal locale (launch locale) and + // deal expiration date if |check_restrictions| is true. + const ServicesCustomizationDocument::CarrierDeal* GetCarrierDeal( + const std::string& carrier_id, bool check_restrictions) const; + + protected: + virtual bool LoadManifestFromString(const std::string& manifest) OVERRIDE; + private: FRIEND_TEST(ServicesCustomizationDocumentTest, Basic); FRIEND_TEST(ServicesCustomizationDocumentTest, BadManifest); + FRIEND_TEST(ServicesCustomizationDocumentTest, DealOtherLocale); + FRIEND_TEST(ServicesCustomizationDocumentTest, NoDealRestrictions); + FRIEND_TEST(ServicesCustomizationDocumentTest, OldDeal); friend struct DefaultSingletonTraits<ServicesCustomizationDocument>; // C-tor for singleton construction. ServicesCustomizationDocument(); // C-tor for test construction. - explicit ServicesCustomizationDocument(const std::string& manifest); + ServicesCustomizationDocument(const std::string& manifest, + const std::string& initial_locale); // Save applied state in machine settings. static void SetApplied(bool val); @@ -158,6 +196,12 @@ class ServicesCustomizationDocument : public CustomizationDocument, // How many times we already tried to fetch customization manifest file. int num_retries_; + // Carrier-specific deals. + CarrierDeals carrier_deals_; + + // Initial locale value. + std::string initial_locale_; + DISALLOW_COPY_AND_ASSIGN(ServicesCustomizationDocument); }; diff --git a/chrome/browser/chromeos/customization_document_unittest.cc b/chrome/browser/chromeos/customization_document_unittest.cc index 370f99c..bafca5d 100644 --- a/chrome/browser/chromeos/customization_document_unittest.cc +++ b/chrome/browser/chromeos/customization_document_unittest.cc @@ -4,6 +4,7 @@ #include "chrome/browser/chromeos/customization_document.h" +#include "base/time.h" #include "chrome/browser/chromeos/mock_system_access.h" #include "testing/gtest/include/gtest/gtest.h" @@ -65,6 +66,43 @@ const char kGoodServicesManifest[] = " \"support_page\": \"http://mario/global\"," " }," " }," + " \"carrier_deals\" : {" + " \"Carrier (country)\" : {" + " \"deal_locale\" : \"en-US\"," + " \"top_up_url\" : \"http://www.carrier.com/\"," + " \"notification_count\" : 1,\n" + " \"expire_date\" : \"31/12/12 0:00\"," + " \"localized_content\" : {" + " \"en-US\" : {" + " \"notification_text\" : \"3G connectivity : Carrier.\"," + " }," + " \"default\" : {" + " \"notification_text\" : \"default_text.\"," + " }," + " }," + " }," + " }," + "}"; + +const char kOldDealServicesManifest[] = + "{" + " \"version\": \"1.0\"," + " \"carrier_deals\" : {" + " \"Carrier (country)\" : {" + " \"deal_locale\" : \"en-US\"," + " \"top_up_url\" : \"http://www.carrier.com/\"," + " \"notification_count\" : 1," + " \"expire_date\" : \"01/01/01 0:00\"," + " \"localized_content\" : {" + " \"en-US\" : {" + " \"notification_text\" : \"en-US text.\"," + " }," + " \"default\" : {" + " \"notification_text\" : \"default_text.\"," + " }," + " }," + " }," + " }," "}"; } // anonymous namespace @@ -87,24 +125,24 @@ TEST(StartupCustomizationDocumentTest, Basic) { Return(true))); StartupCustomizationDocument customization(&mock_system_access, kGoodStartupManifest); - EXPECT_EQ(customization.initial_locale(), "ru-RU"); - EXPECT_EQ(customization.initial_timezone(), "Europe/Moscow"); - EXPECT_EQ(customization.keyboard_layout(), "xkb:ru::rus"); - EXPECT_EQ(customization.registration_url(), "http://www.google.com"); - - EXPECT_EQ(customization.GetHelpPage("en-US"), - "file:///opt/oem/help/en-US/help.html"); - EXPECT_EQ(customization.GetHelpPage("ru-RU"), - "file:///opt/oem/help/ru-RU/help.html"); - EXPECT_EQ(customization.GetHelpPage("ja"), - "file:///opt/oem/help/en/help.html"); - - EXPECT_EQ(customization.GetEULAPage("en-US"), - "file:///opt/oem/eula/en-US/eula.html"); - EXPECT_EQ(customization.GetEULAPage("ru-RU"), - "file:///opt/oem/eula/ru-RU/eula.html"); - EXPECT_EQ(customization.GetEULAPage("ja"), - "file:///opt/oem/eula/en/eula.html"); + EXPECT_EQ("ru-RU", customization.initial_locale()); + EXPECT_EQ("Europe/Moscow", customization.initial_timezone()); + EXPECT_EQ("xkb:ru::rus", customization.keyboard_layout()); + EXPECT_EQ("http://www.google.com", customization.registration_url()); + + EXPECT_EQ("file:///opt/oem/help/en-US/help.html", + customization.GetHelpPage("en-US")); + EXPECT_EQ("file:///opt/oem/help/ru-RU/help.html", + customization.GetHelpPage("ru-RU")); + EXPECT_EQ("file:///opt/oem/help/en/help.html", + customization.GetHelpPage("ja")); + + EXPECT_EQ("file:///opt/oem/eula/en-US/eula.html", + customization.GetEULAPage("en-US")); + EXPECT_EQ("file:///opt/oem/eula/ru-RU/eula.html", + customization.GetEULAPage("ru-RU")); + EXPECT_EQ("file:///opt/oem/eula/en/eula.html", + customization.GetEULAPage("ja")); } TEST(StartupCustomizationDocumentTest, VPD) { @@ -128,9 +166,9 @@ TEST(StartupCustomizationDocumentTest, VPD) { StartupCustomizationDocument customization(&mock_system_access, kGoodStartupManifest); EXPECT_TRUE(customization.IsReady()); - EXPECT_EQ(customization.initial_locale(), "ja"); - EXPECT_EQ(customization.initial_timezone(), "Asia/Tokyo"); - EXPECT_EQ(customization.keyboard_layout(), "mozc-jp"); + EXPECT_EQ("ja", customization.initial_locale()); + EXPECT_EQ("Asia/Tokyo", customization.initial_timezone()); + EXPECT_EQ("mozc-jp", customization.keyboard_layout()); } TEST(StartupCustomizationDocumentTest, BadManifest) { @@ -140,27 +178,75 @@ TEST(StartupCustomizationDocumentTest, BadManifest) { } TEST(ServicesCustomizationDocumentTest, Basic) { - ServicesCustomizationDocument customization(kGoodServicesManifest); + ServicesCustomizationDocument customization(kGoodServicesManifest, "en-US"); + EXPECT_TRUE(customization.IsReady()); + + EXPECT_EQ("http://mario/promo", + customization.GetInitialStartPage("en-US")); + EXPECT_EQ("http://mario/ru/promo", + customization.GetInitialStartPage("ru-RU")); + EXPECT_EQ("http://mario/global/promo", + customization.GetInitialStartPage("ja")); + + EXPECT_EQ("http://mario/us", customization.GetSupportPage("en-US")); + EXPECT_EQ("http://mario/ru", customization.GetSupportPage("ru-RU")); + EXPECT_EQ("http://mario/global", customization.GetSupportPage("ja")); + + const ServicesCustomizationDocument::CarrierDeal* deal; + deal = customization.GetCarrierDeal("Carrier (country)", true); + EXPECT_TRUE(deal != NULL); + EXPECT_EQ("en-US", deal->deal_locale); + EXPECT_EQ("http://www.carrier.com/", deal->top_up_url); + EXPECT_EQ(1, deal->notification_count); + EXPECT_EQ("3G connectivity : Carrier.", + deal->GetLocalizedString("en-US", "notification_text")); + EXPECT_EQ("default_text.", + deal->GetLocalizedString("en", "notification_text")); + + base::Time reference_time; + base::Time::FromString(L"31/12/12 0:00", &reference_time); + EXPECT_EQ(reference_time, deal->expire_date); +} + +TEST(ServicesCustomizationDocumentTest, OldDeal) { + ServicesCustomizationDocument customization(kOldDealServicesManifest, + "en-US"); EXPECT_TRUE(customization.IsReady()); - EXPECT_EQ(customization.GetInitialStartPage("en-US"), - "http://mario/promo"); - EXPECT_EQ(customization.GetInitialStartPage("ru-RU"), - "http://mario/ru/promo"); - EXPECT_EQ(customization.GetInitialStartPage("ja"), - "http://mario/global/promo"); - - EXPECT_EQ(customization.GetSupportPage("en-US"), - "http://mario/us"); - EXPECT_EQ(customization.GetSupportPage("ru-RU"), - "http://mario/ru"); - EXPECT_EQ(customization.GetSupportPage("ja"), - "http://mario/global"); + const ServicesCustomizationDocument::CarrierDeal* deal; + // TODO(nkostylev): Pass fixed time instead of relying on Time::Now(). + deal = customization.GetCarrierDeal("Carrier (country)", true); + EXPECT_TRUE(deal == NULL); +} + +TEST(ServicesCustomizationDocumentTest, DealOtherLocale) { + ServicesCustomizationDocument customization(kGoodServicesManifest, + "en-GB"); + EXPECT_TRUE(customization.IsReady()); + + const ServicesCustomizationDocument::CarrierDeal* deal; + deal = customization.GetCarrierDeal("Carrier (country)", true); + EXPECT_TRUE(deal == NULL); } TEST(ServicesCustomizationDocumentTest, BadManifest) { - ServicesCustomizationDocument customization(kBadManifest); + ServicesCustomizationDocument customization(kBadManifest, "en-US"); EXPECT_FALSE(customization.IsReady()); } +TEST(ServicesCustomizationDocumentTest, NoDealRestrictions) { + ServicesCustomizationDocument customization_oth_locale(kGoodServicesManifest, + "en-GB"); + EXPECT_TRUE(customization_oth_locale.IsReady()); + const ServicesCustomizationDocument::CarrierDeal* deal; + deal = customization_oth_locale.GetCarrierDeal("Carrier (country)", false); + EXPECT_TRUE(deal != NULL); + + ServicesCustomizationDocument customization_old_deal(kOldDealServicesManifest, + "en-US"); + EXPECT_TRUE(customization_old_deal.IsReady()); + deal = customization_old_deal.GetCarrierDeal("Carrier (country)", false); + EXPECT_TRUE(deal != NULL); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/login/base_login_display_host.cc b/chrome/browser/chromeos/login/base_login_display_host.cc index 53fda9a..dff58d0 100644 --- a/chrome/browser/chromeos/login/base_login_display_host.cc +++ b/chrome/browser/chromeos/login/base_login_display_host.cc @@ -146,9 +146,8 @@ void BaseLoginDisplayHost::StartSignInScreen() { SetShutdownButtonEnabled(true); sign_in_controller_->Init(users); - // Initiate service customization manifest fetching. - if (!ServicesCustomizationDocument::WasApplied()) - ServicesCustomizationDocument::GetInstance()->StartFetching(); + // Initiate services customization manifest fetching. + ServicesCustomizationDocument::GetInstance()->StartFetching(); } // BaseLoginDisplayHost -------------------------------------------------------- diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index 446721a..2db09d4 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc @@ -337,7 +337,8 @@ void ExistingUserController::OnProfilePrepared(Profile* profile) { ServicesCustomizationDocument* customization = ServicesCustomizationDocument::GetInstance(); - if (customization->IsReady()) { + if (!ServicesCustomizationDocument::WasApplied() && + customization->IsReady()) { std::string locale = g_browser_process->GetApplicationLocale(); std::string initial_start_page = customization->GetInitialStartPage(locale); diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index c0b5588..6ee4aed 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc @@ -130,6 +130,9 @@ void Preferences::RegisterUserPrefs(PrefService* prefs) { // 3G first-time usage promo will be shown at least once. prefs->RegisterBooleanPref(prefs::kShow3gPromoNotification, true); + + // Carrier deal notification shown count defaults to 0. + prefs->RegisterIntegerPref(prefs::kCarrierDealPromoShown, 0); } void Preferences::Init(PrefService* prefs) { diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc index c9d9cd1..7b2debb 100644 --- a/chrome/browser/chromeos/status/network_menu.cc +++ b/chrome/browser/chromeos/status/network_menu.cc @@ -12,6 +12,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/choose_mobile_network_dialog.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/sim_dialog_delegate.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" @@ -270,6 +271,10 @@ void NetworkMenuModel::ActivatedAt(int index) { const VirtualNetwork* active_vpn = cros->virtual_network(); if (active_vpn) cros->DisconnectFromNetwork(active_vpn); + } else if (flags & FLAG_VIEW_ACCOUNT) { + Browser* browser = BrowserList::GetLastActive(); + if (browser) + browser->ShowSingletonTab(GURL(top_up_url_)); } } @@ -498,18 +503,46 @@ void MainMenuModel::InitMenuItems(bool is_browser_mode, } } const NetworkDevice* cellular_device = cros->FindCellularDevice(); - // TODO(dpolukhin): replace imsi check with more specific supportNetworkScan - if (cellular_device && !cellular_device->imsi().empty()) { - // For GSM add mobile network scan. - if (!separator_added && !menu_items_.empty()) - menu_items_.push_back(MenuItem()); + if (cellular_device) { + // Add "View Account" with top up URL if we know that. + ServicesCustomizationDocument* customization = + ServicesCustomizationDocument::GetInstance(); + if (is_browser_mode && customization->IsReady()) { + std::string carrier_id = cros->GetCellularHomeCarrierId(); + // If we don't have top up URL cached. + if (carrier_id != carrier_id_) { + // Mark that we've checked this carrier ID. + carrier_id_ = carrier_id; + top_up_url_.clear(); + // Ignoring deal restrictions, use any carrier information available. + const ServicesCustomizationDocument::CarrierDeal* deal = + customization->GetCarrierDeal(carrier_id, false); + if (deal && !deal->top_up_url.empty()) + top_up_url_ = deal->top_up_url; + } + if (!top_up_url_.empty()) { + menu_items_.push_back(MenuItem( + ui::MenuModel::TYPE_COMMAND, + l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT), + SkBitmap(), + std::string(), FLAG_VIEW_ACCOUNT)); + } + } - menu_items_.push_back(MenuItem( - ui::MenuModel::TYPE_COMMAND, - l10n_util::GetStringUTF16( - IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS), - *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK), - std::string(), FLAG_ADD_CELLULAR)); + // TODO(dpolukhin): replace imsi check with more specific + // supportNetworkScan. + if (!cellular_device->imsi().empty()) { + // For GSM add mobile network scan. + if (!separator_added && !menu_items_.empty()) + menu_items_.push_back(MenuItem()); + + menu_items_.push_back(MenuItem( + ui::MenuModel::TYPE_COMMAND, + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS), + *rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0_BLACK), + std::string(), FLAG_ADD_CELLULAR)); + } } } diff --git a/chrome/browser/chromeos/status/network_menu.h b/chrome/browser/chromeos/status/network_menu.h index fc80127..660e9f2 100644 --- a/chrome/browser/chromeos/status/network_menu.h +++ b/chrome/browser/chromeos/status/network_menu.h @@ -106,6 +106,7 @@ class NetworkMenuModel : public ui::MenuModel { FLAG_VPN = 1 << 12, FLAG_ADD_VPN = 1 << 13, FLAG_DISCONNECT_VPN = 1 << 14, + FLAG_VIEW_ACCOUNT = 1 << 15, }; struct MenuItem { @@ -143,6 +144,13 @@ class NetworkMenuModel : public ui::MenuModel { NetworkMenu* owner_; // Weak pointer to NetworkMenu that owns this MenuModel. + // Top up URL of the current carrier on empty string if there's none. + std::string top_up_url_; + + // Carrier ID which top up URL is initialized for. + // Used to update top up URL only when cellular carrier has changed. + std::string carrier_id_; + private: // Show a NetworkConfigView modal dialog instance. void ShowNetworkConfigView(NetworkConfigView* view) const; diff --git a/chrome/browser/chromeos/status/network_menu_button.cc b/chrome/browser/chromeos/status/network_menu_button.cc index 3167b2c..85880db 100644 --- a/chrome/browser/chromeos/status/network_menu_button.cc +++ b/chrome/browser/chromeos/status/network_menu_button.cc @@ -10,7 +10,9 @@ #include "base/logging.h" #include "base/message_loop.h" #include "base/string_util.h" +#include "base/stringprintf.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/login/user_manager.h" @@ -32,17 +34,30 @@ namespace { // Time in milliseconds to delay showing of promo // notification when Chrome window is not on screen. -const int kPromoShowDelayMs = 5000; +const int kPromoShowDelayMs = 10000; + +const int kNotificationCountPrefDefault = -1; bool GetBooleanPref(const char* pref_name) { Browser* browser = BrowserList::GetLastActive(); + // Default to safe value which is false (not to show bubble). if (!browser || !browser->profile()) - return true; + return false; PrefService* prefs = browser->profile()->GetPrefs(); return prefs->GetBoolean(pref_name); } +int GetIntegerPref(const char* pref_name) { + Browser* browser = BrowserList::GetLastActive(); + // Default to "safe" value. + if (!browser || !browser->profile()) + return kNotificationCountPrefDefault; + + PrefService* prefs = browser->profile()->GetPrefs(); + return prefs->GetInteger(pref_name); +} + void SetBooleanPref(const char* pref_name, bool value) { Browser* browser = BrowserList::GetLastActive(); if (!browser || !browser->profile()) @@ -52,7 +67,17 @@ void SetBooleanPref(const char* pref_name, bool value) { prefs->SetBoolean(pref_name, value); } -// Returns prefs::kShow3gPromoNotification or true if there's no active browser. +void SetIntegerPref(const char* pref_name, int value) { + Browser* browser = BrowserList::GetLastActive(); + if (!browser || !browser->profile()) + return; + + PrefService* prefs = browser->profile()->GetPrefs(); + prefs->SetInteger(pref_name, value); +} + +// Returns prefs::kShow3gPromoNotification or false +// if there's no active browser. bool ShouldShow3gPromoNotification() { return GetBooleanPref(prefs::kShow3gPromoNotification); } @@ -60,6 +85,16 @@ bool ShouldShow3gPromoNotification() { void SetShow3gPromoNotification(bool value) { SetBooleanPref(prefs::kShow3gPromoNotification, value); } +// Returns prefs::kCarrierDealPromoShown which is number of times +// carrier deal notification has been shown to user or -1 +// if there's no active browser. +int GetCarrierDealPromoShown() { + return GetIntegerPref(prefs::kCarrierDealPromoShown); +} + +void SetCarrierDealPromoShown(int value) { + SetIntegerPref(prefs::kCarrierDealPromoShown, value); +} } // namespace @@ -78,6 +113,7 @@ NetworkMenuButton::NetworkMenuButton(StatusAreaHost* host) right_badge_(NULL), left_badge_(NULL), mobile_data_bubble_(NULL), + check_for_promo_(true), ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { animation_connecting_.SetThrobDuration(kThrobDuration); @@ -187,16 +223,54 @@ void NetworkMenuButton::OnHelpLinkActivated() { // mobile_data_bubble_ will be set to NULL in callback. if (mobile_data_bubble_) mobile_data_bubble_->Close(); - const Network* cellular = - CrosLibrary::Get()->GetNetworkLibrary()->cellular_network(); - if (!cellular) - return; - ShowTabbedNetworkSettings(cellular); + if (!deal_url_.empty()) { + Browser* browser = BrowserList::GetLastActive(); + if (!browser) + return; + browser->ShowSingletonTab(GURL(deal_url_)); + deal_url_.clear(); + } else { + const Network* cellular = + CrosLibrary::Get()->GetNetworkLibrary()->cellular_network(); + if (!cellular) + return; + ShowTabbedNetworkSettings(cellular); + } } //////////////////////////////////////////////////////////////////////////////// // NetworkMenuButton, private methods +const ServicesCustomizationDocument::CarrierDeal* +NetworkMenuButton::GetCarrierDeal( + NetworkLibrary* cros) { + std::string carrier_id = cros->GetCellularHomeCarrierId(); + if (carrier_id.empty()) { + LOG(ERROR) << "Empty carrier ID with a cellular connected."; + return NULL; + } + + ServicesCustomizationDocument* customization = + ServicesCustomizationDocument::GetInstance(); + if (!customization->IsReady()) + return NULL; + + const ServicesCustomizationDocument::CarrierDeal* deal = + customization->GetCarrierDeal(carrier_id, true); + if (deal) { + // Check deal for validity. + int carrier_deal_promo_pref = GetCarrierDealPromoShown(); + if (carrier_deal_promo_pref >= deal->notification_count) + return NULL; + const std::string locale = g_browser_process->GetApplicationLocale(); + std::string deal_text = deal->GetLocalizedString(locale, + "notification_text"); + if (deal_text.empty()) + return NULL; + } + return deal; +} + void NetworkMenuButton::SetIconAndBadges(const SkBitmap* icon, const SkBitmap* right_badge, const SkBitmap* left_badge) { @@ -333,14 +407,26 @@ void NetworkMenuButton::RefreshNetworkDeviceObserver(NetworkLibrary* cros) { void NetworkMenuButton::ShowOptionalMobileDataPromoNotification( NetworkLibrary* cros) { // Display one-time notification for non-Guest users on first use - // of Mobile Data connection. + // of Mobile Data connection or if there's a carrier deal defined + // show that even if user has already seen generic promo. if (IsBrowserMode() && !UserManager::Get()->IsLoggedInAsGuest() && - ShouldShow3gPromoNotification() && + check_for_promo_ && cros->cellular_connected() && !cros->ethernet_connected() && !cros->wifi_connected()) { - const CellularNetwork* cellular = cros->cellular_network(); - if (!cellular) + + const ServicesCustomizationDocument::CarrierDeal* deal = + GetCarrierDeal(cros); + std::string deal_text; + int carrier_deal_promo_pref = -1; + if (deal) { + carrier_deal_promo_pref = GetCarrierDealPromoShown(); + const std::string locale = g_browser_process->GetApplicationLocale(); + deal_text = deal->GetLocalizedString(locale, "notification_text"); + deal_url_ = deal->top_up_url; + } else if (!ShouldShow3gPromoNotification()) { + check_for_promo_ = false; return; + } gfx::Rect button_bounds = GetScreenBounds(); // StatusArea button Y position is usually -1, fix it so that @@ -364,15 +450,38 @@ void NetworkMenuButton::ShowOptionalMobileDataPromoNotification( return; } + // Add deal text if it's defined. + std::wstring notification_text; + std::wstring default_text = + UTF16ToWide(l10n_util::GetStringUTF16(IDS_3G_NOTIFICATION_MESSAGE)); + if (!deal_text.empty()) { + notification_text = StringPrintf(L"%ls\n\n%ls", + UTF8ToWide(deal_text).c_str(), + default_text.c_str()); + } else { + notification_text = default_text; + } + + // Use deal URL if it's defined or general "Network Settings" URL. + int link_message_id; + if (deal_url_.empty()) + link_message_id = IDS_OFFLINE_NETWORK_SETTINGS; + else + link_message_id = IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT; + mobile_data_bubble_ = MessageBubble::Show( GetWidget(), button_bounds, BubbleBorder::TOP_RIGHT , ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_NOTIFICATION_3G), - UTF16ToWide(l10n_util::GetStringUTF16(IDS_3G_NOTIFICATION_MESSAGE)), - UTF16ToWide(l10n_util::GetStringUTF16(IDS_OFFLINE_NETWORK_SETTINGS)), + notification_text, + UTF16ToWide(l10n_util::GetStringUTF16(link_message_id)), this); + + check_for_promo_ = false; SetShow3gPromoNotification(false); + if (carrier_deal_promo_pref != kNotificationCountPrefDefault) + SetCarrierDealPromoShown(carrier_deal_promo_pref + 1); } } diff --git a/chrome/browser/chromeos/status/network_menu_button.h b/chrome/browser/chromeos/status/network_menu_button.h index cba380e..0cae643 100644 --- a/chrome/browser/chromeos/status/network_menu_button.h +++ b/chrome/browser/chromeos/status/network_menu_button.h @@ -11,6 +11,7 @@ #include "base/task.h" #include "base/timer.h" #include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/login/message_bubble.h" #include "chrome/browser/chromeos/status/network_menu.h" #include "chrome/browser/chromeos/status/status_area_button.h" @@ -93,6 +94,11 @@ class NetworkMenuButton : public StatusAreaButton, virtual void OnHelpLinkActivated(); private: + // Returns carrier deal if it's specified and should be shown, + // otherwise returns NULL. + const ServicesCustomizationDocument::CarrierDeal* GetCarrierDeal( + NetworkLibrary* cros); + // Sets the icon and the badges (badges are at the bottom of the icon). void SetIconAndBadges(const SkBitmap* icon, const SkBitmap* right_badge, @@ -129,6 +135,10 @@ class NetworkMenuButton : public StatusAreaButton, // Notification bubble for 3G promo. MessageBubble* mobile_data_bubble_; + // True if check for promo needs to be done, + // otherwise just ignore it for current session. + bool check_for_promo_; + // The throb animation that does the wifi connecting animation. ui::ThrobAnimation animation_connecting_; @@ -139,6 +149,9 @@ class NetworkMenuButton : public StatusAreaButton, // whose status is displayed in the network menu button. std::string active_network_; + // Current carrier deal URL. + std::string deal_url_; + // Factory for delaying showing promo notification. ScopedRunnableMethodFactory<NetworkMenuButton> method_factory_; diff --git a/chrome/browser/extensions/extension_info_private_api_chromeos.cc b/chrome/browser/extensions/extension_info_private_api_chromeos.cc index f5d441d..67a40cb 100644 --- a/chrome/browser/extensions/extension_info_private_api_chromeos.cc +++ b/chrome/browser/extensions/extension_info_private_api_chromeos.cc @@ -53,14 +53,7 @@ bool GetChromeosInfoFunction::GetValue(const std::string& property_name, } else if (property_name == kPropertyHomeProvider) { if (CrosLibrary::Get()->EnsureLoaded()) { NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary(); - const chromeos::NetworkDevice* device = netlib->FindCellularDevice(); - if (device) { - DLOG(INFO) << "Taking the home provider of " << device->name() - << " (" << device->device_path() << ")"; - (*value) = device->home_provider(); - } else { - LOG(WARNING) << "Can't find cellular device."; - } + (*value) = netlib->GetCellularHomeCarrierId(); } else { LOG(ERROR) << "CrosLibrary can't be loaded."; } diff --git a/chrome/browser/resources/options/chromeos/internet_options.js b/chrome/browser/resources/options/chromeos/internet_options.js index 199bb7d..5129247 100644 --- a/chrome/browser/resources/options/chromeos/internet_options.js +++ b/chrome/browser/resources/options/chromeos/internet_options.js @@ -370,7 +370,14 @@ cr.define('options', function() { page.removeAttribute('ethernet'); page.removeAttribute('wireless'); page.setAttribute('cellular', true); - $('serviceName').textContent = data.serviceName; + if (data.carrierUrl) { + var a = $('serviceName').appendChild(document.createElement('a')); + a.href = data.carrierUrl; + a.target = "_blank"; + a.textContent = data.serviceName; + } else { + $('serviceName').textContent = data.serviceName; + } $('networkTechnology').textContent = data.networkTechnology; $('activationState').textContent = data.activationState; $('roamingState').textContent = data.roamingState; diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc index 07607e7..3d17f08 100644 --- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc @@ -22,6 +22,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/choose_mobile_network_dialog.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/sim_dialog_delegate.h" #include "chrome/browser/chromeos/status/network_menu.h" @@ -696,6 +697,16 @@ void InternetOptionsHandler::PopulateCellularDetails( dictionary->SetString("min", device->min()); dictionary->SetBoolean("simCardLockEnabled", device->sim_pin_required() == chromeos::SIM_PIN_REQUIRED); + + chromeos::ServicesCustomizationDocument* customization = + chromeos::ServicesCustomizationDocument::GetInstance(); + if (customization->IsReady()) { + std::string carrier_id = cros->GetCellularHomeCarrierId(); + const chromeos::ServicesCustomizationDocument::CarrierDeal* deal = + customization->GetCarrierDeal(carrier_id, false); + if (deal && !deal->top_up_url.empty()) + dictionary->SetString("carrierUrl", deal->top_up_url); + } } SetActivationButtonVisibility(cellular, dictionary); diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 0e260b1..5d5f400 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -482,6 +482,11 @@ const char kShowPlanNotifications[] = const char kShow3gPromoNotification[] = "settings.internet.mobile.show_3g_promo_notification"; +// An integer pref which shows number of times carrier deal promo +// notification has been shown to user. +const char kCarrierDealPromoShown[] = + "settings.internet.mobile.carrier_deal_promo_shown"; + #endif // defined(OS_CHROMEOS) // The disabled messages in IPC logging. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 17d49ca..5d648b0 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -166,6 +166,7 @@ extern const char kLabsMediaplayerEnabled[]; extern const char kEnableScreenLock[]; extern const char kShowPlanNotifications[]; extern const char kShow3gPromoNotification[]; +extern const char kCarrierDealPromoShown[]; #endif extern const char kIpcDisabledMessages[]; extern const char kShowHomeButton[]; |