diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/system/gonk/TimeZoneSettingObserver.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/system/gonk/TimeZoneSettingObserver.cpp')
-rw-r--r-- | dom/system/gonk/TimeZoneSettingObserver.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/dom/system/gonk/TimeZoneSettingObserver.cpp b/dom/system/gonk/TimeZoneSettingObserver.cpp new file mode 100644 index 000000000..512f79908 --- /dev/null +++ b/dom/system/gonk/TimeZoneSettingObserver.cpp @@ -0,0 +1,239 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "base/message_loop.h" +#include "jsapi.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/Attributes.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/Hal.h" +#include "mozilla/Services.h" +#include "mozilla/StaticPtr.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsIObserver.h" +#include "nsIObserverService.h" +#include "nsISettingsService.h" +#include "nsJSUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsString.h" +#include "TimeZoneSettingObserver.h" +#include "xpcpublic.h" +#include "nsContentUtils.h" +#include "nsPrintfCString.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/SettingChangeNotificationBinding.h" + +#undef LOG +#undef ERR +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args) +#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args) + +#define TIME_TIMEZONE "time.timezone" +#define MOZSETTINGS_CHANGED "mozsettings-changed" + +using namespace mozilla; +using namespace mozilla::dom; + +namespace { + +class TimeZoneSettingObserver : public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + TimeZoneSettingObserver(); + static nsresult SetTimeZone(const JS::Value &aValue, JSContext *aContext); + +protected: + virtual ~TimeZoneSettingObserver(); +}; + +class TimeZoneSettingCb final : public nsISettingsServiceCallback +{ +public: + NS_DECL_ISUPPORTS + + TimeZoneSettingCb() {} + + NS_IMETHOD Handle(const nsAString &aName, JS::Handle<JS::Value> aResult) { + + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + NS_ENSURE_TRUE(cx, NS_OK); + + // If we don't have time.timezone value in the settings, we need + // to initialize the settings based on the current system timezone + // to make settings consistent with system. This usually happens + // at the very first boot. After that, settings must have a value. + if (aResult.isNull()) { + // Get the current system time zone offset. Note that we need to + // convert the value to a UTC representation in the format of + // "UTC{+,-}hh:mm", so that the Gaia end can know how to interpret. + // E.g., -480 is "UTC+08:00"; 630 is "UTC-10:30". + int32_t timeZoneOffset = hal::GetTimezoneOffset(); + nsPrintfCString curTimeZone("UTC%+03d:%02d", + -timeZoneOffset / 60, + abs(timeZoneOffset) % 60); + + // Convert it to a JS string. + NS_ConvertUTF8toUTF16 utf16Str(curTimeZone); + + JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx, + utf16Str.get(), + utf16Str.Length())); + if (!jsStr) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // Set the settings based on the current system timezone. + nsCOMPtr<nsISettingsServiceLock> lock; + nsCOMPtr<nsISettingsService> settingsService = + do_GetService("@mozilla.org/settingsService;1"); + if (!settingsService) { + ERR("Failed to get settingsLock service!"); + return NS_OK; + } + settingsService->CreateLock(nullptr, getter_AddRefs(lock)); + JS::Rooted<JS::Value> value(cx, JS::StringValue(jsStr)); + lock->Set(TIME_TIMEZONE, value, nullptr, nullptr); + return NS_OK; + } + + // Set the system timezone based on the current settings. + if (aResult.isString()) { + return TimeZoneSettingObserver::SetTimeZone(aResult, cx); + } + + return NS_OK; + } + + NS_IMETHOD HandleError(const nsAString &aName) { + ERR("TimeZoneSettingCb::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); + return NS_OK; + } + +protected: + ~TimeZoneSettingCb() {} +}; + +NS_IMPL_ISUPPORTS(TimeZoneSettingCb, nsISettingsServiceCallback) + +TimeZoneSettingObserver::TimeZoneSettingObserver() +{ + // Setup an observer to watch changes to the setting. + nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); + if (!observerService) { + ERR("GetObserverService failed"); + return; + } + nsresult rv; + rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); + if (NS_FAILED(rv)) { + ERR("AddObserver failed"); + return; + } + + // Read the 'time.timezone' setting in order to start with a known + // value at boot time. The handle() will be called after reading. + nsCOMPtr<nsISettingsServiceLock> lock; + nsCOMPtr<nsISettingsService> settingsService = + do_GetService("@mozilla.org/settingsService;1"); + if (!settingsService) { + ERR("Failed to get settingsLock service!"); + return; + } + settingsService->CreateLock(nullptr, getter_AddRefs(lock)); + nsCOMPtr<nsISettingsServiceCallback> callback = new TimeZoneSettingCb(); + lock->Get(TIME_TIMEZONE, callback); +} + +nsresult TimeZoneSettingObserver::SetTimeZone(const JS::Value &aValue, JSContext *aContext) +{ + // Convert the JS value to a nsCString type. + // The value should be a JS string like "America/Chicago" or "UTC-05:00". + nsAutoJSString valueStr; + if (!valueStr.init(aContext, aValue.toString())) { + ERR("Failed to convert JS value to nsCString"); + return NS_ERROR_FAILURE; + } + NS_ConvertUTF16toUTF8 newTimezone(valueStr); + + // Hal expects opposite sign from general notations, + // so we need to flip it. + if (newTimezone.Find(NS_LITERAL_CSTRING("UTC+")) == 0) { + if (!newTimezone.SetCharAt('-', 3)) { + return NS_ERROR_FAILURE; + } + } else if (newTimezone.Find(NS_LITERAL_CSTRING("UTC-")) == 0) { + if (!newTimezone.SetCharAt('+', 3)) { + return NS_ERROR_FAILURE; + } + } + + // Set the timezone only when the system timezone is not identical. + nsCString curTimezone = hal::GetTimezone(); + if (!curTimezone.Equals(newTimezone)) { + hal::SetTimezone(newTimezone); + } + + return NS_OK; +} + +TimeZoneSettingObserver::~TimeZoneSettingObserver() +{ + nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); + if (observerService) { + observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); + } +} + +NS_IMPL_ISUPPORTS(TimeZoneSettingObserver, nsIObserver) + +NS_IMETHODIMP +TimeZoneSettingObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { + return NS_OK; + } + + // Note that this function gets called for any and all settings changes, + // so we need to carefully check if we have the one we're interested in. + // + // The string that we're interested in will be a JSON string that looks like: + // {"key":"time.timezone","value":"America/Chicago"} or + // {"key":"time.timezone","value":"UTC-05:00"} + + AutoSafeJSContext cx; + RootedDictionary<SettingChangeNotification> setting(cx); + if (!WrappedJSToDictionary(cx, aSubject, setting)) { + return NS_OK; + } + if (!setting.mKey.EqualsASCII(TIME_TIMEZONE)) { + return NS_OK; + } + if (!setting.mValue.isString()) { + return NS_OK; + } + + // Set the system timezone. + return SetTimeZone(setting.mValue, cx); +} + +} // namespace + +static mozilla::StaticRefPtr<TimeZoneSettingObserver> sTimeZoneSettingObserver; +namespace mozilla { +namespace system { +void +InitializeTimeZoneSettingObserver() +{ + sTimeZoneSettingObserver = new TimeZoneSettingObserver(); + ClearOnShutdown(&sTimeZoneSettingObserver); +} + +} // namespace system +} // namespace mozilla |