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

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

Powered by Google App Engine
This is Rietveld 408576698