Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: chrome/browser/chromeos/system/timezone_settings.cc

Issue 10689175: Refactored code for timezone settings. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Added comment referring to initialization in ui.conf. Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/system/timezone_settings.h" 5 #include "chrome/browser/chromeos/system/timezone_settings.h"
6 6
7 #include <string>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/chromeos/chromeos_version.h" 10 #include "base/chromeos/chromeos_version.h"
9 #include "base/file_path.h" 11 #include "base/file_path.h"
10 #include "base/file_util.h" 12 #include "base/file_util.h"
11 #include "base/logging.h" 13 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/singleton.h" 15 #include "base/memory/singleton.h"
14 #include "base/observer_list.h" 16 #include "base/observer_list.h"
17 #include "base/stl_util.h"
15 #include "base/string_util.h" 18 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
17 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/browser_thread.h"
18 21
19 using content::BrowserThread; 22 using content::BrowserThread;
20 23
21 namespace chromeos {
22 namespace system {
23
24 namespace { 24 namespace {
25 25
26 // The filepath to the timezone file that symlinks to the actual timezone file. 26 // The filepath to the timezone file that symlinks to the actual timezone file.
27 const char kTimezoneSymlink[] = "/var/lib/timezone/localtime"; 27 const char kTimezoneSymlink[] = "/var/lib/timezone/localtime";
28 const char kTimezoneSymlink2[] = "/var/lib/timezone/localtime2"; 28 const char kTimezoneSymlink2[] = "/var/lib/timezone/localtime2";
29 29
30 // The directory that contains all the timezone files. So for timezone 30 // The directory that contains all the timezone files. So for timezone
31 // "US/Pacific", the actual timezone file is: "/usr/share/zoneinfo/US/Pacific" 31 // "US/Pacific", the actual timezone file is: "/usr/share/zoneinfo/US/Pacific"
32 const char kTimezoneFilesDir[] = "/usr/share/zoneinfo/"; 32 const char kTimezoneFilesDir[] = "/usr/share/zoneinfo/";
33 33
34 // Fallback time zone ID used in case of an unexpected error. 34 // Fallback time zone ID used in case of an unexpected error.
35 const char kFallbackTimeZoneId[] = "America/Los_Angeles"; 35 const char kFallbackTimeZoneId[] = "America/Los_Angeles";
36 36
37 } // namespace 37 // TODO(jungshik): Using Enumerate method in ICU gives 600+ timezones.
38 38 // Even after filtering out duplicate entries with a strict identity check,
39 // The TimezoneSettings implementation used in production. 39 // we still have 400+ zones. Relaxing the criteria for the timezone
40 class TimezoneSettingsImpl : public TimezoneSettings { 40 // identity is likely to cut down the number to < 100. Until we
41 public: 41 // come up with a better list, we hard-code the following list as used by
42 // TimezoneSettings implementation: 42 // Android.
43 virtual const icu::TimeZone& GetTimezone(); 43 static const char* kTimeZones[] = {
44 virtual void SetTimezone(const icu::TimeZone& timezone); 44 "Pacific/Majuro",
45 virtual void AddObserver(Observer* observer); 45 "Pacific/Midway",
46 virtual void RemoveObserver(Observer* observer); 46 "Pacific/Honolulu",
47 47 "America/Anchorage",
48 static TimezoneSettingsImpl* GetInstance(); 48 "America/Los_Angeles",
49 49 "America/Tijuana",
50 private: 50 "America/Denver",
51 friend struct DefaultSingletonTraits<TimezoneSettingsImpl>; 51 "America/Phoenix",
52 52 "America/Chihuahua",
53 TimezoneSettingsImpl(); 53 "America/Chicago",
54 54 "America/Mexico_City",
55 scoped_ptr<icu::TimeZone> timezone_; 55 "America/Costa_Rica",
56 ObserverList<Observer> observers_; 56 "America/Regina",
57 57 "America/New_York",
58 DISALLOW_COPY_AND_ASSIGN(TimezoneSettingsImpl); 58 "America/Bogota",
59 "America/Caracas",
60 "America/Barbados",
61 "America/Manaus",
62 "America/Santiago",
63 "America/St_Johns",
64 "America/Sao_Paulo",
65 "America/Araguaina",
66 "America/Argentina/Buenos_Aires",
67 "America/Godthab",
68 "America/Montevideo",
69 "Atlantic/South_Georgia",
70 "Atlantic/Azores",
71 "Atlantic/Cape_Verde",
72 "Africa/Casablanca",
73 "Europe/London",
74 "Europe/Amsterdam",
75 "Europe/Belgrade",
76 "Europe/Brussels",
77 "Europe/Sarajevo",
78 "Africa/Windhoek",
79 "Africa/Brazzaville",
80 "Asia/Amman",
81 "Europe/Athens",
82 "Asia/Beirut",
83 "Africa/Cairo",
84 "Europe/Helsinki",
85 "Asia/Jerusalem",
86 "Europe/Minsk",
87 "Africa/Harare",
88 "Asia/Baghdad",
89 "Europe/Moscow",
90 "Asia/Kuwait",
91 "Africa/Nairobi",
92 "Asia/Tehran",
93 "Asia/Baku",
94 "Asia/Tbilisi",
95 "Asia/Yerevan",
96 "Asia/Dubai",
97 "Asia/Kabul",
98 "Asia/Karachi",
99 "Asia/Oral",
100 "Asia/Yekaterinburg",
101 "Asia/Calcutta",
102 "Asia/Colombo",
103 "Asia/Katmandu",
104 "Asia/Almaty",
105 "Asia/Rangoon",
106 "Asia/Krasnoyarsk",
107 "Asia/Bangkok",
108 "Asia/Shanghai",
109 "Asia/Hong_Kong",
110 "Asia/Irkutsk",
111 "Asia/Kuala_Lumpur",
112 "Australia/Perth",
113 "Asia/Taipei",
114 "Asia/Seoul",
115 "Asia/Tokyo",
116 "Asia/Yakutsk",
117 "Australia/Adelaide",
118 "Australia/Darwin",
119 "Australia/Brisbane",
120 "Australia/Hobart",
121 "Australia/Sydney",
122 "Asia/Vladivostok",
123 "Pacific/Guam",
124 "Asia/Magadan",
125 "Pacific/Auckland",
126 "Pacific/Fiji",
127 "Pacific/Tongatapu",
59 }; 128 };
60 129
61 std::string GetTimezoneIDAsString() { 130 std::string GetTimezoneIDAsString() {
131 // Compare with chromiumos/src/platform/init/ui.conf which fixes certain
132 // incorrect states of the timezone symlink on startup. Thus errors occuring
133 // here should be rather contrived.
134
62 // Look at kTimezoneSymlink, see which timezone we are symlinked to. 135 // Look at kTimezoneSymlink, see which timezone we are symlinked to.
63 char buf[256]; 136 char buf[256];
64 const ssize_t len = readlink(kTimezoneSymlink, buf, 137 const ssize_t len = readlink(kTimezoneSymlink, buf,
65 sizeof(buf)-1); 138 sizeof(buf)-1);
66 if (len == -1) { 139 if (len == -1) {
67 LOG(ERROR) << "GetTimezoneID: Cannot read timezone symlink " 140 LOG(ERROR) << "GetTimezoneID: Cannot read timezone symlink "
68 << kTimezoneSymlink; 141 << kTimezoneSymlink;
69 return std::string(); 142 return std::string();
70 } 143 }
71 144
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 } 181 }
109 182
110 // Move symlink2 to symlink. 183 // Move symlink2 to symlink.
111 if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) { 184 if (!file_util::ReplaceFile(timezone_symlink2, timezone_symlink)) {
112 LOG(ERROR) << "SetTimezoneID: Unable to move symlink " 185 LOG(ERROR) << "SetTimezoneID: Unable to move symlink "
113 << timezone_symlink2.value() << " to " 186 << timezone_symlink2.value() << " to "
114 << timezone_symlink.value(); 187 << timezone_symlink.value();
115 } 188 }
116 } 189 }
117 190
118 const icu::TimeZone& TimezoneSettingsImpl::GetTimezone() { 191 // Common code of the TimezoneSettings implementations.
192 class TimezoneSettingsBaseImpl : public chromeos::system::TimezoneSettings {
193 public:
194 virtual ~TimezoneSettingsBaseImpl();
195
196 // TimezoneSettings implementation:
197 virtual const icu::TimeZone& GetTimezone();
198 virtual const string16 GetCurrentTimezoneID();
199 virtual void SetTimezoneFromID(const string16& timezone_id);
200 virtual void AddObserver(Observer* observer);
201 virtual void RemoveObserver(Observer* observer);
202 virtual const std::vector<icu::TimeZone*> &GetTimezoneList() const;
Joao da Silva 2012/07/12 18:34:09 Mark all of these with OVERRIDE.
pneubeck2 2012/07/13 10:31:39 Done.
203
204 protected:
205 TimezoneSettingsBaseImpl();
206
207 // Returns |timezone| if it is an element of |timezones_|.
208 // Otherwise, returns a timezone from |timezones_|, if such exists, that has
209 // the same rule as the given |timezone|.
210 // Otherwise, returns NULL.
211 // Note multiple timezones with the same time zone offset may exist
212 // e.g.
213 // US/Pacific == America/Los_Angeles
214 const icu::TimeZone *GetKnownTimezoneOrNull(
Joao da Silva 2012/07/12 18:34:09 Nit: move * next to the return type
pneubeck2 2012/07/13 10:31:39 Done.
215 const icu::TimeZone& timezone) const;
216
217 ObserverList<Observer> observers_;
218 std::vector<icu::TimeZone*> timezones_;
219 scoped_ptr<icu::TimeZone> timezone_;
220
221 private:
222 DISALLOW_COPY_AND_ASSIGN(TimezoneSettingsBaseImpl);
223 };
224
225 TimezoneSettingsBaseImpl::~TimezoneSettingsBaseImpl() {
226 STLDeleteElements(&timezones_);
227 }
228
229 const icu::TimeZone& TimezoneSettingsBaseImpl::GetTimezone() {
119 return *timezone_.get(); 230 return *timezone_.get();
120 } 231 }
121 232
233 const string16 TimezoneSettingsBaseImpl::GetCurrentTimezoneID() {
Joao da Silva 2012/07/12 18:34:09 No need for const when returning by value.
pneubeck2 2012/07/13 10:31:39 Done.
234 return chromeos::system::TimezoneSettings::GetTimezoneID(GetTimezone());
235 }
236
237 void TimezoneSettingsBaseImpl::SetTimezoneFromID(const string16& timezone_id) {
238 scoped_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone(
239 icu::UnicodeString(timezone_id.c_str(), timezone_id.size())));
240 SetTimezone(*timezone);
241 }
242
243 void TimezoneSettingsBaseImpl::AddObserver(Observer* observer) {
244 observers_.AddObserver(observer);
245 }
246
247 void TimezoneSettingsBaseImpl::RemoveObserver(Observer* observer) {
248 observers_.RemoveObserver(observer);
249 }
250
251 const std::vector<icu::TimeZone*> &
252 TimezoneSettingsBaseImpl::GetTimezoneList() const {
253 return timezones_;
254 }
255
256 TimezoneSettingsBaseImpl::TimezoneSettingsBaseImpl() {
257 for (size_t i = 0; i < arraysize(kTimeZones); i++) {
Joao da Silva 2012/07/12 18:34:09 Nit: ++i
pneubeck2 2012/07/13 10:31:39 Done.
258 timezones_.push_back(icu::TimeZone::createTimeZone(
259 icu::UnicodeString(kTimeZones[i], -1, US_INV)));
260 }
261 }
262
263 const icu::TimeZone *TimezoneSettingsBaseImpl::GetKnownTimezoneOrNull(
Joao da Silva 2012/07/12 18:34:09 Nit: move * next to the return type
pneubeck2 2012/07/13 10:31:39 Done.
264 const icu::TimeZone& timezone) const {
265 const icu::TimeZone* known_timezone = NULL;
266 for (std::vector<icu::TimeZone*>::const_iterator iter = timezones_.begin();
267 iter != timezones_.end(); ++iter) {
268 const icu::TimeZone* entry = *iter;
269 if (*entry == timezone)
270 return entry;
271 if (entry->hasSameRules(timezone))
272 known_timezone = entry;
273 }
274
275 // May return NULL if we did not find a matching timezone in our list.
276 return known_timezone;
277 }
278
279 // The TimezoneSettings implementation used in production.
280 class TimezoneSettingsImpl : public TimezoneSettingsBaseImpl {
Joao da Silva 2012/07/12 18:34:09 Put all the class declarations first in the file,
pneubeck2 2012/07/13 10:31:39 Done.
281 public:
282 // TimezoneSettings implementation:
283 virtual void SetTimezone(const icu::TimeZone& timezone);
Joao da Silva 2012/07/12 18:34:09 OVERRIDE
pneubeck2 2012/07/13 10:31:39 Done.
284
285 static TimezoneSettingsImpl* GetInstance();
286
287 private:
288
289 friend struct DefaultSingletonTraits<TimezoneSettingsImpl>;
Joao da Silva 2012/07/12 18:34:09 Nit: remove the empty line above. Add DISALLOW_COP
pneubeck2 2012/07/13 10:31:39 Done.
290
291 TimezoneSettingsImpl();
292 };
293
122 void TimezoneSettingsImpl::SetTimezone(const icu::TimeZone& timezone) { 294 void TimezoneSettingsImpl::SetTimezone(const icu::TimeZone& timezone) {
123 timezone_.reset(timezone.clone()); 295 // replace |timezone| by a known timezone with the same rules. if
124 icu::UnicodeString unicode; 296 // none exists go on with |timezone|.
Joao da Silva 2012/07/12 18:34:09 Start both sentences in uppercase.
pneubeck2 2012/07/13 10:31:39 Done.
125 timezone.getID(unicode); 297 const icu::TimeZone *known_timezone = GetKnownTimezoneOrNull(timezone);
Joao da Silva 2012/07/12 18:34:09 Nit: * next to the type
pneubeck2 2012/07/13 10:31:39 Done.
126 std::string id; 298 if (!known_timezone)
127 UTF16ToUTF8(unicode.getBuffer(), unicode.length(), &id); 299 known_timezone = &timezone;
300
301 timezone_.reset(known_timezone->clone());
302 std::string id = UTF16ToUTF8(GetTimezoneID(*known_timezone));
128 VLOG(1) << "Setting timezone to " << id; 303 VLOG(1) << "Setting timezone to " << id;
129 // Change the timezone config files on the FILE thread. It's safe to do this 304 // Change the timezone config files on the FILE thread. It's safe to do this
130 // in the background as the following operations don't depend on the 305 // in the background as the following operations don't depend on the
131 // completion of the config change. 306 // completion of the config change.
132 BrowserThread::PostTask(BrowserThread::FILE, 307 BrowserThread::PostTask(BrowserThread::FILE,
Joao da Silva 2012/07/12 18:34:09 Post to the blocking pool instead: BrowserThread:
pneubeck2 2012/07/13 10:31:39 Done.
133 FROM_HERE, 308 FROM_HERE,
134 base::Bind(&SetTimezoneIDFromString, id)); 309 base::Bind(&SetTimezoneIDFromString, id));
135 icu::TimeZone::setDefault(timezone); 310 icu::TimeZone::setDefault(*known_timezone);
136 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(timezone)); 311 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(*known_timezone));
137 }
138
139 void TimezoneSettingsImpl::AddObserver(Observer* observer) {
140 observers_.AddObserver(observer);
141 }
142
143 void TimezoneSettingsImpl::RemoveObserver(Observer* observer) {
144 observers_.RemoveObserver(observer);
145 }
146
147 TimezoneSettingsImpl::TimezoneSettingsImpl() {
148 // Get Timezone
149 std::string id = GetTimezoneIDAsString();
150 if (id.empty()) {
151 id = kFallbackTimeZoneId;
152 LOG(ERROR) << "Got an empty string for timezone, default to " << id;
153 }
154 icu::TimeZone* timezone =
155 icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(id));
156 timezone_.reset(timezone);
157 icu::TimeZone::setDefault(*timezone);
158 VLOG(1) << "Timezone is " << id;
159 } 312 }
160 313
161 TimezoneSettingsImpl* TimezoneSettingsImpl::GetInstance() { 314 TimezoneSettingsImpl* TimezoneSettingsImpl::GetInstance() {
162 return Singleton<TimezoneSettingsImpl, 315 return Singleton<TimezoneSettingsImpl,
163 DefaultSingletonTraits<TimezoneSettingsImpl> >::get(); 316 DefaultSingletonTraits<TimezoneSettingsImpl> >::get();
164 } 317 }
165 318
319 TimezoneSettingsImpl::TimezoneSettingsImpl() {
320 std::string id = GetTimezoneIDAsString();
321 if (id.empty()) {
322 id = kFallbackTimeZoneId;
323 LOG(ERROR) << "Got an empty string for timezone, default to '" << id;
324 }
325
326 timezone_.reset(icu::TimeZone::createTimeZone(
327 icu::UnicodeString::fromUTF8(id)));
328
329 // Store a known timezone equivalent to id in |timezone_|.
330 const icu::TimeZone *known_timezone = GetKnownTimezoneOrNull(*timezone_);
Joao da Silva 2012/07/12 18:34:09 Nit: move * next to type
pneubeck2 2012/07/13 10:31:39 Done.
331 if (known_timezone != NULL && *known_timezone != *timezone_)
332 // Not necessary to update the filesystem because |known_timezone| has the
333 // same rules.
334 timezone_.reset(known_timezone->clone());
335
336 icu::TimeZone::setDefault(*timezone_);
337 VLOG(1) << "Timezone initially set to " << id;
338 }
339
166 // The stub TimezoneSettings implementation used on Linux desktop. 340 // The stub TimezoneSettings implementation used on Linux desktop.
167 class TimezoneSettingsStubImpl : public TimezoneSettings { 341 class TimezoneSettingsStubImpl : public TimezoneSettingsBaseImpl {
Joao da Silva 2012/07/12 18:34:09 Declare all classes before defining method impleme
pneubeck2 2012/07/13 10:31:39 Done.
168 public: 342 public:
169 // TimezoneSettings implementation: 343 // TimezoneSettings implementation:
170 virtual const icu::TimeZone& GetTimezone() { 344 virtual void SetTimezone(const icu::TimeZone& timezone) {
Joao da Silva 2012/07/12 18:34:09 OVERRIDE
pneubeck2 2012/07/13 10:31:39 Done.
171 return *timezone_.get(); 345 // replace |timezone| by a known timezone with the same rules. if
172 } 346 // none exists go on with |timezone|.
Joao da Silva 2012/07/12 18:34:09 Start both sentences in uppercase.
pneubeck2 2012/07/13 10:31:39 Done.
347 const icu::TimeZone *known_timezone = GetKnownTimezoneOrNull(timezone);
348 if (!known_timezone)
349 known_timezone = &timezone;
173 350
174 virtual void SetTimezone(const icu::TimeZone& timezone) { 351 timezone_.reset(known_timezone->clone());
175 icu::TimeZone::setDefault(timezone); 352 icu::TimeZone::setDefault(*known_timezone);
176 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(timezone)); 353 FOR_EACH_OBSERVER(Observer, observers_, TimezoneChanged(*known_timezone));
177 }
178
179 virtual void AddObserver(Observer* observer) {
180 observers_.AddObserver(observer);
181 }
182
183 virtual void RemoveObserver(Observer* observer) {
184 observers_.RemoveObserver(observer);
185 } 354 }
186 355
187 static TimezoneSettingsStubImpl* GetInstance() { 356 static TimezoneSettingsStubImpl* GetInstance() {
188 return Singleton<TimezoneSettingsStubImpl, 357 return Singleton<TimezoneSettingsStubImpl,
189 DefaultSingletonTraits<TimezoneSettingsStubImpl> >::get(); 358 DefaultSingletonTraits<TimezoneSettingsStubImpl> >::get();
190 } 359 }
191 360
192 private: 361 private:
193 friend struct DefaultSingletonTraits<TimezoneSettingsStubImpl>; 362 friend struct DefaultSingletonTraits<TimezoneSettingsStubImpl>;
194 363
195 TimezoneSettingsStubImpl() { 364 TimezoneSettingsStubImpl() {
196 timezone_.reset(icu::TimeZone::createDefault()); 365 timezone_.reset(icu::TimeZone::createDefault());
366 const icu::TimeZone *known_timezone = GetKnownTimezoneOrNull(*timezone_);
Joao da Silva 2012/07/12 18:34:09 Nit: move * next to the type
pneubeck2 2012/07/13 10:31:39 Done.
367 if (known_timezone != NULL && *known_timezone != *timezone_)
368 timezone_.reset(known_timezone->clone());
197 } 369 }
Joao da Silva 2012/07/12 18:34:09 DISALLOW_COPY_AND_ASSIGN
pneubeck2 2012/07/13 10:31:39 Done.
370 };
198 371
199 scoped_ptr<icu::TimeZone> timezone_; 372 } // namespace
200 ObserverList<Observer> observers_;
201 373
202 DISALLOW_COPY_AND_ASSIGN(TimezoneSettingsStubImpl); 374 namespace chromeos {
203 }; 375 namespace system {
204 376
205 TimezoneSettings* TimezoneSettings::GetInstance() { 377 TimezoneSettings* TimezoneSettings::GetInstance() {
206 if (base::chromeos::IsRunningOnChromeOS()) { 378 if (base::chromeos::IsRunningOnChromeOS()) {
207 return TimezoneSettingsImpl::GetInstance(); 379 return TimezoneSettingsImpl::GetInstance();
208 } else { 380 } else {
209 return TimezoneSettingsStubImpl::GetInstance(); 381 return TimezoneSettingsStubImpl::GetInstance();
210 } 382 }
211 } 383 }
212 384
385 string16 TimezoneSettings::GetTimezoneID(
Joao da Silva 2012/07/12 18:34:09 Add a comment before this line like this: // stat
pneubeck2 2012/07/13 10:31:39 Done.
386 const icu::TimeZone& timezone) {
Joao da Silva 2012/07/12 18:34:09 No need to break the previous line?
pneubeck2 2012/07/13 10:31:39 Done.
387 icu::UnicodeString id;
388 timezone.getID(id);
389 return string16(id.getBuffer(), id.length());
390 }
391
392
Joao da Silva 2012/07/12 18:34:09 Nit: remove extra newline
pneubeck2 2012/07/13 10:31:39 Done.
213 } // namespace system 393 } // namespace system
214 } // namespace chromeos 394 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698