Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / mobile_config.cc
blob6e560f888180fcce28c45b0bfa287f83a9a46e18
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/chromeos/mobile_config.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_reader.h"
13 #include "base/logging.h"
14 #include "base/stl_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chromeos/login/startup_utils.h"
18 #include "content/public/browser/browser_thread.h"
20 using content::BrowserThread;
22 namespace {
24 // Config attributes names.
25 const char kAcceptedConfigVersion[] = "1.0";
26 const char kDefaultAttr[] = "default";
28 // Carrier config attributes.
29 const char kCarriersAttr[] = "carriers";
30 const char kCarrierIdsAttr[] = "ids";
31 const char kCarrierIdAttr[] = "id";
32 const char kTopUpURLAttr[] = "top_up_url";
33 const char kShowPortalButtonAttr[] = "show_portal_button";
34 const char kDealsAttr[] = "deals";
36 // Carrier deal attributes.
37 const char kDealIdAttr[] = "deal_id";
38 const char kDealLocalesAttr[] = "locales";
40 const char kInfoURLAttr[] = "info_url";
41 const char kNotificationCountAttr[] = "notification_count";
42 const char kDealExpireDateAttr[] = "expire_date";
43 const char kLocalizedContentAttr[] = "localized_content";
45 // Initial locale carrier config attributes.
46 const char kInitialLocalesAttr[] = "initial_locales";
47 const char kSetupURLAttr[] = "setup_url";
49 // Local config properties.
50 const char kExcludeDealsAttr[] = "exclude_deals";
52 // Location of the global carrier config.
53 const char kGlobalCarrierConfigPath[] =
54 "/usr/share/chromeos-assets/mobile/carrier_config.json";
56 // Location of the local carrier config.
57 const char kLocalCarrierConfigPath[] =
58 "/opt/oem/etc/carrier_config.json";
60 } // anonymous namespace
62 namespace chromeos {
64 // MobileConfig::CarrierDeal implementation. -----------------------------------
66 MobileConfig::CarrierDeal::CarrierDeal(const base::DictionaryValue* deal_dict)
67 : notification_count_(0),
68 localized_strings_(NULL) {
69 deal_dict->GetString(kDealIdAttr, &deal_id_);
71 // Extract list of deal locales.
72 const base::ListValue* locale_list = NULL;
73 if (deal_dict->GetList(kDealLocalesAttr, &locale_list)) {
74 for (size_t i = 0; i < locale_list->GetSize(); ++i) {
75 std::string locale;
76 if (locale_list->GetString(i, &locale))
77 locales_.push_back(locale);
81 deal_dict->GetString(kInfoURLAttr, &info_url_);
82 deal_dict->GetInteger(kNotificationCountAttr, &notification_count_);
83 std::string date_string;
84 if (deal_dict->GetString(kDealExpireDateAttr, &date_string)) {
85 if (!base::Time::FromString(date_string.c_str(), &expire_date_))
86 LOG(ERROR) << "Error parsing deal_expire_date: " << date_string;
88 deal_dict->GetDictionary(kLocalizedContentAttr, &localized_strings_);
91 MobileConfig::CarrierDeal::~CarrierDeal() {
94 std::string MobileConfig::CarrierDeal::GetLocalizedString(
95 const std::string& locale, const std::string& id) const {
96 std::string result;
97 if (localized_strings_) {
98 const base::DictionaryValue* locale_dict = NULL;
99 if (localized_strings_->GetDictionary(locale, &locale_dict) &&
100 locale_dict->GetString(id, &result)) {
101 return result;
102 } else if (localized_strings_->GetDictionary(kDefaultAttr, &locale_dict) &&
103 locale_dict->GetString(id, &result)) {
104 return result;
107 return result;
110 // MobileConfig::Carrier implementation. ---------------------------------------
112 MobileConfig::Carrier::Carrier(const base::DictionaryValue* carrier_dict,
113 const std::string& initial_locale)
114 : show_portal_button_(false) {
115 InitFromDictionary(carrier_dict, initial_locale);
118 MobileConfig::Carrier::~Carrier() {
119 RemoveDeals();
122 const MobileConfig::CarrierDeal* MobileConfig::Carrier::GetDefaultDeal() const {
123 // TODO(nkostylev): Use carrier "default_deal_id" attribute.
124 CarrierDeals::const_iterator iter = deals_.begin();
125 if (iter != deals_.end())
126 return GetDeal((*iter).first);
127 else
128 return NULL;
131 const MobileConfig::CarrierDeal* MobileConfig::Carrier::GetDeal(
132 const std::string& deal_id) const {
133 CarrierDeals::const_iterator iter = deals_.find(deal_id);
134 if (iter != deals_.end()) {
135 CarrierDeal* deal = iter->second;
136 // Make sure that deal is still active,
137 // i.e. if deal expire date is defined, check it.
138 if (!deal->expire_date().is_null() &&
139 deal->expire_date() <= base::Time::Now()) {
140 return NULL;
142 return deal;
143 } else {
144 return NULL;
148 void MobileConfig::Carrier::InitFromDictionary(
149 const base::DictionaryValue* carrier_dict,
150 const std::string& initial_locale) {
151 carrier_dict->GetString(kTopUpURLAttr, &top_up_url_);
152 carrier_dict->GetBoolean(kShowPortalButtonAttr, &show_portal_button_);
154 bool exclude_deals = false;
155 if (carrier_dict->GetBoolean(kExcludeDealsAttr, &exclude_deals) &&
156 exclude_deals) {
157 RemoveDeals();
160 // Extract list of external IDs for this carrier.
161 const base::ListValue* id_list = NULL;
162 if (carrier_dict->GetList(kCarrierIdsAttr, &id_list)) {
163 for (size_t i = 0; i < id_list->GetSize(); ++i) {
164 const base::DictionaryValue* id_dict = NULL;
165 std::string external_id;
166 if (id_list->GetDictionary(i, &id_dict) &&
167 id_dict->GetString(kCarrierIdAttr, &external_id)) {
168 external_ids_.push_back(external_id);
173 // Extract list of deals for this carrier.
174 const base::ListValue* deals_list = NULL;
175 if (carrier_dict->GetList(kDealsAttr, &deals_list)) {
176 for (size_t i = 0; i < deals_list->GetSize(); ++i) {
177 const base::DictionaryValue* deal_dict = NULL;
178 if (deals_list->GetDictionary(i, &deal_dict)) {
179 scoped_ptr<CarrierDeal> deal(new CarrierDeal(deal_dict));
180 // Filter out deals by initial_locale right away.
181 std::vector<std::string>::const_iterator iter =
182 std::find(deal->locales().begin(),
183 deal->locales().end(),
184 initial_locale);
185 if (iter != deal->locales().end()) {
186 const std::string& deal_id = deal->deal_id();
187 deals_[deal_id] = deal.release();
194 void MobileConfig::Carrier::RemoveDeals() {
195 STLDeleteValues(&deals_);
198 // MobileConfig::LocaleConfig implementation. ----------------------------------
200 MobileConfig::LocaleConfig::LocaleConfig(base::DictionaryValue* locale_dict) {
201 InitFromDictionary(locale_dict);
204 MobileConfig::LocaleConfig::~LocaleConfig() {
207 void MobileConfig::LocaleConfig::InitFromDictionary(
208 base::DictionaryValue* locale_dict) {
209 locale_dict->GetString(kSetupURLAttr, &setup_url_);
212 // MobileConfig implementation, public -----------------------------------------
214 // static
215 MobileConfig* MobileConfig::GetInstance() {
216 return base::Singleton<MobileConfig,
217 base::DefaultSingletonTraits<MobileConfig>>::get();
220 const MobileConfig::Carrier* MobileConfig::GetCarrier(
221 const std::string& carrier_id) const {
222 CarrierIdMap::const_iterator id_iter = carrier_id_map_.find(carrier_id);
223 std::string internal_id;
224 if (id_iter != carrier_id_map_.end())
225 internal_id = id_iter->second;
226 else
227 return NULL;
228 Carriers::const_iterator iter = carriers_.find(internal_id);
229 if (iter != carriers_.end())
230 return iter->second;
231 else
232 return NULL;
235 const MobileConfig::LocaleConfig* MobileConfig::GetLocaleConfig() const {
236 return locale_config_.get();
239 // MobileConfig implementation, protected --------------------------------------
241 bool MobileConfig::LoadManifestFromString(const std::string& manifest) {
242 if (!CustomizationDocument::LoadManifestFromString(manifest))
243 return false;
245 // Local config specific attribute.
246 bool exclude_deals = false;
247 if (root_.get() &&
248 root_->GetBoolean(kExcludeDealsAttr, &exclude_deals) &&
249 exclude_deals) {
250 for (Carriers::iterator iter = carriers_.begin();
251 iter != carriers_.end(); ++iter) {
252 iter->second->RemoveDeals();
256 // Other parts are optional and are the same among global/local config.
257 base::DictionaryValue* carriers = NULL;
258 if (root_.get() && root_->GetDictionary(kCarriersAttr, &carriers)) {
259 for (base::DictionaryValue::Iterator iter(*carriers); !iter.IsAtEnd();
260 iter.Advance()) {
261 const base::DictionaryValue* carrier_dict = NULL;
262 if (iter.value().GetAsDictionary(&carrier_dict)) {
263 const std::string& internal_id = iter.key();
264 Carriers::iterator inner_iter = carriers_.find(internal_id);
265 if (inner_iter != carriers_.end()) {
266 // Carrier already defined i.e. loading from the local config.
267 // New ID mappings in local config is not supported.
268 inner_iter->second->InitFromDictionary(carrier_dict, initial_locale_);
269 } else {
270 Carrier* carrier = new Carrier(carrier_dict, initial_locale_);
271 if (!carrier->external_ids().empty()) {
272 // Map all external IDs to a single internal one.
273 for (std::vector<std::string>::const_iterator
274 i = carrier->external_ids().begin();
275 i != carrier->external_ids().end(); ++i) {
276 carrier_id_map_[*i] = internal_id;
278 } else {
279 // Trivial case - using same ID for external/internal one.
280 carrier_id_map_[internal_id] = internal_id;
282 carriers_[internal_id] = carrier;
288 base::DictionaryValue* initial_locales = NULL;
289 if (root_.get() && root_->GetDictionary(kInitialLocalesAttr,
290 &initial_locales)) {
291 base::DictionaryValue* locale_config_dict = NULL;
292 // Search for a config based on current initial locale.
293 if (initial_locales->GetDictionary(initial_locale_,
294 &locale_config_dict)) {
295 locale_config_.reset(new LocaleConfig(locale_config_dict));
299 return true;
302 // MobileConfig implementation, private ----------------------------------------
304 MobileConfig::MobileConfig()
305 : CustomizationDocument(kAcceptedConfigVersion),
306 initial_locale_(StartupUtils::GetInitialLocale()) {
307 LoadConfig();
310 MobileConfig::MobileConfig(const std::string& config,
311 const std::string& initial_locale)
312 : CustomizationDocument(kAcceptedConfigVersion),
313 initial_locale_(initial_locale) {
314 LoadManifestFromString(config);
317 MobileConfig::~MobileConfig() {
318 STLDeleteValues(&carriers_);
321 void MobileConfig::LoadConfig() {
322 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
323 base::Bind(&MobileConfig::ReadConfigInBackground,
324 base::Unretained(this), // this class is a singleton.
325 base::FilePath(kGlobalCarrierConfigPath),
326 base::FilePath(kLocalCarrierConfigPath)));
329 void MobileConfig::ProcessConfig(const std::string& global_config,
330 const std::string& local_config) {
331 // Global config is mandatory, local config is optional.
332 bool global_initialized = false;
333 bool local_initialized = true;
334 scoped_ptr<base::DictionaryValue> global_config_root;
336 if (!global_config.empty()) {
337 global_initialized = LoadManifestFromString(global_config);
338 // Backup global config root as it might be
339 // owerwritten while loading local config.
340 global_config_root.reset(root_.release());
342 if (!local_config.empty())
343 local_initialized = LoadManifestFromString(local_config);
345 // Treat any parser errors as fatal.
346 if (!global_initialized || !local_initialized) {
347 root_.reset(NULL);
348 local_config_root_.reset(NULL);
349 } else {
350 local_config_root_.reset(root_.release());
351 root_.reset(global_config_root.release());
355 void MobileConfig::ReadConfigInBackground(
356 const base::FilePath& global_config_file,
357 const base::FilePath& local_config_file) {
358 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
359 std::string global_config;
360 std::string local_config;
361 if (!base::ReadFileToString(global_config_file, &global_config)) {
362 VLOG(1) << "Failed to load global mobile config from: "
363 << global_config_file.value();
365 if (!base::ReadFileToString(local_config_file, &local_config)) {
366 VLOG(1) << "Failed to load local mobile config from: "
367 << local_config_file.value();
369 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
370 base::Bind(&MobileConfig::ProcessConfig,
371 base::Unretained(this), // singleton.
372 global_config,
373 local_config));
376 } // namespace chromeos