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/file_path.h"
11 #include "base/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/wizard_controller.h"
18 #include "content/public/browser/browser_thread.h"
20 using content::BrowserThread
;
24 // Config attributes names.
25 const char kVersionAttr
[] = "version";
26 const char kAcceptedConfigVersion
[] = "1.0";
27 const char kDefaultAttr
[] = "default";
29 // Carrier config attributes.
30 const char kCarriersAttr
[] = "carriers";
31 const char kCarrierIdsAttr
[] = "ids";
32 const char kCarrierIdAttr
[] = "id";
33 const char kTopUpURLAttr
[] = "top_up_url";
34 const char kShowPortalButtonAttr
[] = "show_portal_button";
35 const char kDealsAttr
[] = "deals";
37 // Carrier deal attributes.
38 const char kDealIdAttr
[] = "deal_id";
39 const char kDealLocalesAttr
[] = "locales";
41 const char kInfoURLAttr
[] = "info_url";
42 const char kNotificationCountAttr
[] = "notification_count";
43 const char kDealExpireDateAttr
[] = "expire_date";
44 const char kLocalizedContentAttr
[] = "localized_content";
45 const char kNotificationTextAttr
[] = "notification_text";
47 // Initial locale carrier config attributes.
48 const char kInitialLocalesAttr
[] = "initial_locales";
49 const char kSetupURLAttr
[] = "setup_url";
51 // Local config properties.
52 const char kExcludeDealsAttr
[] = "exclude_deals";
54 // Location of the global carrier config.
55 const char kGlobalCarrierConfigPath
[] =
56 "/usr/share/chromeos-assets/mobile/carrier_config.json";
58 // Location of the local carrier config.
59 const char kLocalCarrierConfigPath
[] =
60 "/opt/oem/etc/carrier_config.json";
62 } // anonymous namespace
66 // MobileConfig::CarrierDeal implementation. -----------------------------------
68 MobileConfig::CarrierDeal::CarrierDeal(DictionaryValue
* deal_dict
)
69 : notification_count_(0),
70 localized_strings_(NULL
) {
71 deal_dict
->GetString(kDealIdAttr
, &deal_id_
);
73 // Extract list of deal locales.
74 ListValue
* locale_list
= NULL
;
75 if (deal_dict
->GetList(kDealLocalesAttr
, &locale_list
)) {
76 for (size_t i
= 0; i
< locale_list
->GetSize(); ++i
) {
78 if (locale_list
->GetString(i
, &locale
))
79 locales_
.push_back(locale
);
83 deal_dict
->GetString(kInfoURLAttr
, &info_url_
);
84 deal_dict
->GetInteger(kNotificationCountAttr
, ¬ification_count_
);
85 std::string date_string
;
86 if (deal_dict
->GetString(kDealExpireDateAttr
, &date_string
)) {
87 if (!base::Time::FromString(date_string
.c_str(), &expire_date_
))
88 LOG(ERROR
) << "Error parsing deal_expire_date: " << date_string
;
90 deal_dict
->GetDictionary(kLocalizedContentAttr
, &localized_strings_
);
93 MobileConfig::CarrierDeal::~CarrierDeal() {
96 std::string
MobileConfig::CarrierDeal::GetLocalizedString(
97 const std::string
& locale
, const std::string
& id
) const {
99 if (localized_strings_
) {
100 DictionaryValue
* locale_dict
= NULL
;
101 if (localized_strings_
->GetDictionary(locale
, &locale_dict
) &&
102 locale_dict
->GetString(id
, &result
)) {
104 } else if (localized_strings_
->GetDictionary(kDefaultAttr
, &locale_dict
) &&
105 locale_dict
->GetString(id
, &result
)) {
112 // MobileConfig::Carrier implementation. ---------------------------------------
114 MobileConfig::Carrier::Carrier(DictionaryValue
* carrier_dict
,
115 const std::string
& initial_locale
)
116 : show_portal_button_(false) {
117 InitFromDictionary(carrier_dict
, initial_locale
);
120 MobileConfig::Carrier::~Carrier() {
124 const MobileConfig::CarrierDeal
* MobileConfig::Carrier::GetDefaultDeal() const {
125 // TODO(nkostylev): Use carrier "default_deal_id" attribute.
126 CarrierDeals::const_iterator iter
= deals_
.begin();
127 if (iter
!= deals_
.end())
128 return GetDeal((*iter
).first
);
133 const MobileConfig::CarrierDeal
* MobileConfig::Carrier::GetDeal(
134 const std::string
& deal_id
) const {
135 CarrierDeals::const_iterator iter
= deals_
.find(deal_id
);
136 if (iter
!= deals_
.end()) {
137 CarrierDeal
* deal
= iter
->second
;
138 // Make sure that deal is still active,
139 // i.e. if deal expire date is defined, check it.
140 if (!deal
->expire_date().is_null() &&
141 deal
->expire_date() <= base::Time::Now()) {
150 void MobileConfig::Carrier::InitFromDictionary(
151 base::DictionaryValue
* carrier_dict
, const std::string
& initial_locale
) {
152 carrier_dict
->GetString(kTopUpURLAttr
, &top_up_url_
);
153 carrier_dict
->GetBoolean(kShowPortalButtonAttr
, &show_portal_button_
);
155 bool exclude_deals
= false;
156 if (carrier_dict
->GetBoolean(kExcludeDealsAttr
, &exclude_deals
) &&
161 // Extract list of external IDs for this carrier.
162 ListValue
* id_list
= NULL
;
163 if (carrier_dict
->GetList(kCarrierIdsAttr
, &id_list
)) {
164 for (size_t i
= 0; i
< id_list
->GetSize(); ++i
) {
165 DictionaryValue
* id_dict
= NULL
;
166 std::string external_id
;
167 if (id_list
->GetDictionary(i
, &id_dict
) &&
168 id_dict
->GetString(kCarrierIdAttr
, &external_id
)) {
169 external_ids_
.push_back(external_id
);
174 // Extract list of deals for this carrier.
175 ListValue
* deals_list
= NULL
;
176 if (carrier_dict
->GetList(kDealsAttr
, &deals_list
)) {
177 for (size_t i
= 0; i
< deals_list
->GetSize(); ++i
) {
178 DictionaryValue
* deal_dict
= NULL
;
179 if (deals_list
->GetDictionary(i
, &deal_dict
)) {
180 scoped_ptr
<CarrierDeal
> deal(new CarrierDeal(deal_dict
));
181 // Filter out deals by initial_locale right away.
182 std::vector
<std::string
>::const_iterator iter
=
183 std::find(deal
->locales().begin(),
184 deal
->locales().end(),
186 if (iter
!= deal
->locales().end()) {
187 const std::string
& deal_id
= deal
->deal_id();
188 deals_
[deal_id
] = deal
.release();
195 void MobileConfig::Carrier::RemoveDeals() {
196 STLDeleteValues(&deals_
);
199 // MobileConfig::LocaleConfig implementation. ----------------------------------
201 MobileConfig::LocaleConfig::LocaleConfig(DictionaryValue
* locale_dict
) {
202 InitFromDictionary(locale_dict
);
205 MobileConfig::LocaleConfig::~LocaleConfig() {
208 void MobileConfig::LocaleConfig::InitFromDictionary(
209 base::DictionaryValue
* locale_dict
) {
210 locale_dict
->GetString(kSetupURLAttr
, &setup_url_
);
213 // MobileConfig implementation, public -----------------------------------------
216 MobileConfig
* MobileConfig::GetInstance() {
217 return Singleton
<MobileConfig
,
218 DefaultSingletonTraits
<MobileConfig
> >::get();
221 const MobileConfig::Carrier
* MobileConfig::GetCarrier(
222 const std::string
& carrier_id
) const {
223 CarrierIdMap::const_iterator id_iter
= carrier_id_map_
.find(carrier_id
);
224 std::string internal_id
;
225 if (id_iter
!= carrier_id_map_
.end())
226 internal_id
= id_iter
->second
;
229 Carriers::const_iterator iter
= carriers_
.find(internal_id
);
230 if (iter
!= carriers_
.end())
236 const MobileConfig::LocaleConfig
* MobileConfig::GetLocaleConfig() const {
237 return locale_config_
.get();
240 // MobileConfig implementation, protected --------------------------------------
242 bool MobileConfig::LoadManifestFromString(const std::string
& manifest
) {
243 if (!CustomizationDocument::LoadManifestFromString(manifest
))
246 // Local config specific attribute.
247 bool exclude_deals
= false;
249 root_
->GetBoolean(kExcludeDealsAttr
, &exclude_deals
) &&
251 for (Carriers::iterator iter
= carriers_
.begin();
252 iter
!= carriers_
.end(); ++iter
) {
253 iter
->second
->RemoveDeals();
257 // Other parts are optional and are the same among global/local config.
258 DictionaryValue
* carriers
= NULL
;
259 if (root_
.get() && root_
->GetDictionary(kCarriersAttr
, &carriers
)) {
260 for (DictionaryValue::key_iterator iter
= carriers
->begin_keys();
261 iter
!= carriers
->end_keys(); ++iter
) {
262 DictionaryValue
* carrier_dict
= NULL
;
263 if (carriers
->GetDictionary(*iter
, &carrier_dict
)) {
264 const std::string
& internal_id
= *iter
;
265 Carriers::iterator iter
= carriers_
.find(internal_id
);
266 if (iter
!= carriers_
.end()) {
267 // Carrier already defined i.e. loading from the local config.
268 // New ID mappings in local config is not supported.
269 iter
->second
->InitFromDictionary(carrier_dict
, initial_locale_
);
271 Carrier
* carrier
= new Carrier(carrier_dict
, initial_locale_
);
272 if (!carrier
->external_ids().empty()) {
273 // Map all external IDs to a single internal one.
274 for (std::vector
<std::string
>::const_iterator
275 i
= carrier
->external_ids().begin();
276 i
!= carrier
->external_ids().end(); ++i
) {
277 carrier_id_map_
[*i
] = internal_id
;
280 // Trivial case - using same ID for external/internal one.
281 carrier_id_map_
[internal_id
] = internal_id
;
283 carriers_
[internal_id
] = carrier
;
289 DictionaryValue
* initial_locales
= NULL
;
290 if (root_
.get() && root_
->GetDictionary(kInitialLocalesAttr
,
292 DictionaryValue
* locale_config_dict
= NULL
;
293 // Search for a config based on current initial locale.
294 if (initial_locales
->GetDictionary(initial_locale_
,
295 &locale_config_dict
)) {
296 locale_config_
.reset(new LocaleConfig(locale_config_dict
));
303 // MobileConfig implementation, private ----------------------------------------
305 MobileConfig::MobileConfig()
306 : CustomizationDocument(kAcceptedConfigVersion
),
307 initial_locale_(WizardController::GetInitialLocale()) {
311 MobileConfig::MobileConfig(const std::string
& config
,
312 const std::string
& initial_locale
)
313 : CustomizationDocument(kAcceptedConfigVersion
),
314 initial_locale_(initial_locale
) {
315 LoadManifestFromString(config
);
318 MobileConfig::~MobileConfig() {
319 STLDeleteValues(&carriers_
);
322 void MobileConfig::LoadConfig() {
323 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
324 base::Bind(&MobileConfig::ReadConfigInBackground
,
325 base::Unretained(this), // this class is a singleton.
326 FilePath(kGlobalCarrierConfigPath
),
327 FilePath(kLocalCarrierConfigPath
)));
330 void MobileConfig::ProcessConfig(const std::string
& global_config
,
331 const std::string
& local_config
) {
332 // Global config is mandatory, local config is optional.
333 bool global_initialized
= false;
334 bool local_initialized
= true;
335 scoped_ptr
<base::DictionaryValue
> global_config_root
;
337 if (!global_config
.empty()) {
338 global_initialized
= LoadManifestFromString(global_config
);
339 // Backup global config root as it might be
340 // owerwritten while loading local config.
341 global_config_root
.reset(root_
.release());
343 if (!local_config
.empty())
344 local_initialized
= LoadManifestFromString(local_config
);
346 // Treat any parser errors as fatal.
347 if (!global_initialized
|| !local_initialized
) {
349 local_config_root_
.reset(NULL
);
351 local_config_root_
.reset(root_
.release());
352 root_
.reset(global_config_root
.release());
356 void MobileConfig::ReadConfigInBackground(const FilePath
& global_config_file
,
357 const FilePath
& local_config_file
) {
358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
359 std::string global_config
;
360 std::string local_config
;
361 if (!file_util::ReadFileToString(global_config_file
, &global_config
)) {
362 VLOG(1) << "Failed to load global mobile config from: "
363 << global_config_file
.value();
365 if (!file_util::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