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"
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
;
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
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
) {
76 if (locale_list
->GetString(i
, &locale
))
77 locales_
.push_back(locale
);
81 deal_dict
->GetString(kInfoURLAttr
, &info_url_
);
82 deal_dict
->GetInteger(kNotificationCountAttr
, ¬ification_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 {
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
)) {
102 } else if (localized_strings_
->GetDictionary(kDefaultAttr
, &locale_dict
) &&
103 locale_dict
->GetString(id
, &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() {
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
);
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()) {
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
) &&
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(),
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 -----------------------------------------
215 MobileConfig
* MobileConfig::GetInstance() {
216 return Singleton
<MobileConfig
,
217 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
;
228 Carriers::const_iterator iter
= carriers_
.find(internal_id
);
229 if (iter
!= carriers_
.end())
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
))
245 // Local config specific attribute.
246 bool exclude_deals
= false;
248 root_
->GetBoolean(kExcludeDealsAttr
, &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();
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_
);
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
;
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
,
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
));
302 // MobileConfig implementation, private ----------------------------------------
304 MobileConfig::MobileConfig()
305 : CustomizationDocument(kAcceptedConfigVersion
),
306 initial_locale_(StartupUtils::GetInitialLocale()) {
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
) {
348 local_config_root_
.reset(NULL
);
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.
376 } // namespace chromeos