Bug 801096 - [settings] Set-Automatically for time should take effect *immediately* instead of waiting on next NITZ coming (part 1). r=jlebar
authorGene Lian <clian@mozilla.com>
Tue, 23 Oct 2012 15:15:43 +0800
changeset 111134 19e5770f482ad129b3ec142f3e7a230a80817a61
parent 111133 3a30e45e50e2b1f11c247b12d2987a3ab99b2a41
child 111135 97474744374cc0fd21ba479abaa05acf1342668d
push id23730
push userryanvm@gmail.com
push dateWed, 24 Oct 2012 02:28:59 +0000
treeherderautoland@93cc1ee94291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs801096
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 801096 - [settings] Set-Automatically for time should take effect *immediately* instead of waiting on next NITZ coming (part 1). r=jlebar
dom/alarm/AlarmHalService.cpp
dom/alarm/AlarmHalService.h
dom/time/DateCacheCleaner.cpp
dom/time/TimeChangeObserver.cpp
dom/time/TimeChangeObserver.h
hal/Hal.cpp
hal/Hal.h
hal/HalInternal.h
hal/HalTypes.h
hal/fallback/FallbackTime.cpp
hal/gonk/GonkHal.cpp
hal/sandbox/PHal.ipdl
hal/sandbox/SandboxHal.cpp
--- a/dom/alarm/AlarmHalService.cpp
+++ b/dom/alarm/AlarmHalService.cpp
@@ -14,39 +14,39 @@ NS_IMPL_ISUPPORTS1(AlarmHalService, nsIA
 
 void
 AlarmHalService::Init()
 {
   mAlarmEnabled = RegisterTheOneAlarmObserver(this);
   if (!mAlarmEnabled) {
     return;
   }
-  RegisterSystemTimeChangeObserver(this);
+  RegisterSystemTimezoneChangeObserver(this);
 }
 
 /* virtual */ AlarmHalService::~AlarmHalService() 
 {
   if (mAlarmEnabled) {
     UnregisterTheOneAlarmObserver();
-    UnregisterSystemTimeChangeObserver(this);
+    UnregisterSystemTimezoneChangeObserver(this);
   }
 }
 
 /* static */ StaticRefPtr<AlarmHalService> AlarmHalService::sSingleton;
 
-/* static */ already_AddRefed<nsIAlarmHalService>
+/* static */ already_AddRefed<AlarmHalService>
 AlarmHalService::GetInstance()
 {
   if (!sSingleton) {
     sSingleton = new AlarmHalService();
     sSingleton->Init(); 
     ClearOnShutdown(&sSingleton);
   }
 
-  nsCOMPtr<nsIAlarmHalService> service(do_QueryInterface(sSingleton));
+  nsRefPtr<AlarmHalService> service = sSingleton.get();
   return service.forget();
 }
 
 NS_IMETHODIMP
 AlarmHalService::SetAlarm(int32_t aSeconds, int32_t aNanoseconds, bool* aStatus)
 {
   if (!mAlarmEnabled) {
     return NS_ERROR_FAILURE;
@@ -71,42 +71,30 @@ AlarmHalService::SetAlarmFiredCb(nsIAlar
 NS_IMETHODIMP
 AlarmHalService::SetTimezoneChangedCb(nsITimezoneChangedCb* aTimeZoneChangedCb)
 {
   mTimezoneChangedCb = aTimeZoneChangedCb;
   return NS_OK;
 }
 
 void
-AlarmHalService::Notify(const mozilla::void_t& aVoid)
+AlarmHalService::Notify(const void_t& aVoid)
 {
   if (!mAlarmFiredCb) {
     return;
   }
   mAlarmFiredCb->OnAlarmFired();
 }
 
 void
-AlarmHalService::Notify(const SystemTimeChange& aReason)
+AlarmHalService::Notify(
+  const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
 {
-  if (aReason != SYS_TIME_CHANGE_TZ || !mTimezoneChangedCb) {
+  if (!mTimezoneChangedCb) {
     return;
   }
-  mTimezoneChangedCb->OnTimezoneChanged(GetTimezoneOffset(false));
-}
-
-int32_t
-AlarmHalService::GetTimezoneOffset(bool aIgnoreDST)
-{
-  PRExplodedTime prTime;
-  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
-
-  int32_t offset = prTime.tm_params.tp_gmt_offset;
-  if (!aIgnoreDST) {
-    offset += prTime.tm_params.tp_dst_offset;
-  }
-
-  return -(offset / 60);
+  mTimezoneChangedCb->OnTimezoneChanged(
+    aSystemTimezoneChangeInfo.newTimezoneOffsetMinutes());
 }
 
 } // alarm
 } // dom
 } // mozilla
--- a/dom/alarm/AlarmHalService.h
+++ b/dom/alarm/AlarmHalService.h
@@ -8,50 +8,48 @@
 #include "base/basictypes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Services.h"
 #include "nsIAlarmHalService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 namespace alarm {
-
-using namespace hal;
+  
+typedef Observer<void_t> AlarmObserver;
+typedef Observer<hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
 class AlarmHalService : public nsIAlarmHalService, 
                         public AlarmObserver,
-                        public SystemTimeObserver
+                        public SystemTimezoneChangeObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIALARMHALSERVICE
 
   void Init();
   virtual ~AlarmHalService();
 
-  static already_AddRefed<nsIAlarmHalService> GetInstance();
+  static already_AddRefed<AlarmHalService> GetInstance();
 
   // Implementing hal::AlarmObserver
-  void Notify(const mozilla::void_t& aVoid);
+  void Notify(const void_t& aVoid);
 
-  // Implementing hal::SystemTimeObserver
-  void Notify(const SystemTimeChange& aReason);
+  // Implementing hal::SystemTimezoneChangeObserver
+  void Notify(const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
 
 private:
   bool mAlarmEnabled;
   static StaticRefPtr<AlarmHalService> sSingleton;
 
   nsCOMPtr<nsIAlarmFiredCb> mAlarmFiredCb;
   nsCOMPtr<nsITimezoneChangedCb> mTimezoneChangedCb;
-
-  int32_t GetTimezoneOffset(bool aIgnoreDST);
 };
 
 } // namespace alarm
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_alarm_AlarmHalService_h
--- a/dom/time/DateCacheCleaner.cpp
+++ b/dom/time/DateCacheCleaner.cpp
@@ -11,34 +11,30 @@
 #include "mozilla/StaticPtr.h"
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace dom {
 namespace time {
 
-class DateCacheCleaner : public SystemTimeChangeObserver
+class DateCacheCleaner : public SystemTimezoneChangeObserver
 {
 public:
   DateCacheCleaner()
   {
-    RegisterSystemTimeChangeObserver(this);
+    RegisterSystemTimezoneChangeObserver(this);
   }
 
   ~DateCacheCleaner()
   {
-    UnregisterSystemTimeChangeObserver(this);
+    UnregisterSystemTimezoneChangeObserver(this);
   }
-  void Notify(const SystemTimeChange& aReason)
+  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
   {
-    if (aReason == SYS_TIME_CHANGE_CLOCK) {
-      return;
-    }
-
     nsCOMPtr<nsIThreadJSContextStack> stack =
       do_GetService("@mozilla.org/js/xpc/ContextStack;1");
     if (!stack) {
       NS_WARNING("Failed to get JSContextStack");
     }
     JSContext *cx = stack->GetSafeJSContext();
     if (!cx) {
       NS_WARNING("Failed to GetSafeJSContext");
--- a/dom/time/TimeChangeObserver.cpp
+++ b/dom/time/TimeChangeObserver.cpp
@@ -4,39 +4,42 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TimeChangeObserver.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsPIDOMWindow.h"
 #include "nsDOMEvent.h"
 #include "nsContentUtils.h"
+#include "nsIObserverService.h"
 
+using namespace mozilla;
 using namespace mozilla::hal;
-using namespace mozilla;
+using namespace mozilla::services;
 
 StaticAutoPtr<nsSystemTimeChangeObserver> sObserver;
 
 nsSystemTimeChangeObserver* nsSystemTimeChangeObserver::GetInstance()
 {
   if (!sObserver) {
     sObserver = new nsSystemTimeChangeObserver();
     ClearOnShutdown(&sObserver);
   }
   return sObserver;
 }
 
 nsSystemTimeChangeObserver::~nsSystemTimeChangeObserver()
 {
   mWindowListeners.Clear();
-  UnregisterSystemTimeChangeObserver(this);
+  UnregisterSystemClockChangeObserver(this);
+  UnregisterSystemTimezoneChangeObserver(this);
 }
 
 void
-nsSystemTimeChangeObserver::Notify(const SystemTimeChange& aReason)
+nsSystemTimeChangeObserver::FireMozTimeChangeEvent()
 {
   //Copy mWindowListeners and iterate over windowListeners instead because
   //mWindowListeners may be modified while we loop.
   nsTArray<nsWeakPtr> windowListeners;
   for (uint32_t i = 0; i < mWindowListeners.Length(); i++) {
     windowListeners.AppendElement(mWindowListeners.SafeElementAt(i));
   }
 
@@ -53,16 +56,38 @@ nsSystemTimeChangeObserver::Notify(const
     }
 
     nsContentUtils::DispatchTrustedEvent(document, window,
       NS_LITERAL_STRING("moztimechange"), /* bubbles = */ true,
       /* canceable = */ false);
   }
 }
 
+void
+nsSystemTimeChangeObserver::Notify(const int64_t& aClockDeltaMS)
+{
+  // Notify observers that the system clock has been adjusted.
+  nsCOMPtr<nsIObserverService> observerService = GetObserverService();
+  if (observerService) {
+    nsString dataStr;
+    dataStr.AppendFloat(static_cast<double>(aClockDeltaMS));
+    observerService->NotifyObservers(
+      nullptr, "system-clock-change", dataStr.get());
+  }
+
+  FireMozTimeChangeEvent();
+}
+
+void
+nsSystemTimeChangeObserver::Notify(
+  const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+{
+  FireMozTimeChangeEvent();
+}
+
 nsresult
 nsSystemTimeChangeObserver::AddWindowListener(nsIDOMWindow* aWindow)
 {
   return GetInstance()->AddWindowListenerImpl(aWindow);
 }
 
 nsresult
 nsSystemTimeChangeObserver::AddWindowListenerImpl(nsIDOMWindow* aWindow)
@@ -75,17 +100,18 @@ nsSystemTimeChangeObserver::AddWindowLis
   NS_ASSERTION(windowWeakRef, "nsIDOMWindow implementations shuld support weak ref");
 
   if (mWindowListeners.IndexOf(windowWeakRef) !=
       nsTArray<nsIDOMWindow*>::NoIndex) {
     return NS_OK;
   }
 
   if (mWindowListeners.Length() == 0) {
-    RegisterSystemTimeChangeObserver(sObserver);
+    RegisterSystemClockChangeObserver(sObserver);
+    RegisterSystemTimezoneChangeObserver(sObserver);
   }
 
   mWindowListeners.AppendElement(windowWeakRef);
   return NS_OK;
 }
 
 nsresult
 nsSystemTimeChangeObserver::RemoveWindowListener(nsIDOMWindow* aWindow)
@@ -98,13 +124,14 @@ nsSystemTimeChangeObserver::RemoveWindow
 }
 
 nsresult
 nsSystemTimeChangeObserver::RemoveWindowListenerImpl(nsIDOMWindow* aWindow)
 {
   mWindowListeners.RemoveElement(NS_GetWeakReference(aWindow));
 
   if (mWindowListeners.Length() == 0) {
-    UnregisterSystemTimeChangeObserver(sObserver);
+    UnregisterSystemClockChangeObserver(sObserver);
+    UnregisterSystemTimezoneChangeObserver(sObserver);
   }
 
   return NS_OK;
 }
--- a/dom/time/TimeChangeObserver.h
+++ b/dom/time/TimeChangeObserver.h
@@ -7,26 +7,36 @@
 #define _mozilla_time_change_observer_h_
 
 #include "mozilla/Hal.h"
 #include "mozilla/Observer.h"
 #include "mozilla/HalTypes.h"
 #include "nsPIDOMWindow.h"
 #include "nsWeakPtr.h"
 
-typedef mozilla::Observer<mozilla::hal::SystemTimeChange> SystemTimeChangeObserver;
+typedef mozilla::Observer<int64_t> SystemClockChangeObserver;
+typedef mozilla::Observer<mozilla::hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
-class nsSystemTimeChangeObserver : public SystemTimeChangeObserver
+class nsSystemTimeChangeObserver : public SystemClockChangeObserver,
+                                   public SystemTimezoneChangeObserver
 {
 public:
   static nsSystemTimeChangeObserver* GetInstance();
   virtual ~nsSystemTimeChangeObserver();
-  void Notify(const mozilla::hal::SystemTimeChange& aReason);
+
+  // Implementing hal::SystemClockChangeObserver::Notify()
+  void Notify(const int64_t& aClockDeltaMS);
+
+  // Implementing hal::SystemTimezoneChangeObserver::Notify()
+  void Notify(
+    const mozilla::hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
+
   static nsresult AddWindowListener(nsIDOMWindow* aWindow);
   static nsresult RemoveWindowListener(nsIDOMWindow* aWindow);
 private:
   nsresult AddWindowListenerImpl(nsIDOMWindow* aWindow);
   nsresult RemoveWindowListenerImpl(nsIDOMWindow* aWindow);
   nsSystemTimeChangeObserver() { };
   nsTArray<nsWeakPtr> mWindowListeners;
+  void FireMozTimeChangeEvent();
 };
 
 #endif //_mozilla_time_change_observer_h_
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -400,62 +400,96 @@ double GetScreenBrightness()
 }
 
 void SetScreenBrightness(double brightness)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
 }
 
-bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
+bool SetLight(LightType light, const LightConfiguration& aConfig)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig), false);
 }
 
-bool GetLight(LightType light, hal::LightConfiguration* aConfig)
+bool GetLight(LightType light, LightConfiguration* aConfig)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig), false);
 }
 
-class SystemTimeObserversManager : public ObserversManager<SystemTimeChange>
+class SystemClockChangeObserversManager : public ObserversManager<int64_t>
 {
 protected:
   void EnableNotifications() {
-    PROXY_IF_SANDBOXED(EnableSystemTimeChangeNotifications());
+    PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications());
   }
 
   void DisableNotifications() {
-    PROXY_IF_SANDBOXED(DisableSystemTimeChangeNotifications());
+    PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications());
   }
 };
 
-static SystemTimeObserversManager sSystemTimeObservers;
+static SystemClockChangeObserversManager sSystemClockChangeObservers;
 
 void
-RegisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
+RegisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
 {
   AssertMainThread();
-  sSystemTimeObservers.AddObserver(aObserver);
+  sSystemClockChangeObservers.AddObserver(aObserver);
+}
+
+void
+UnregisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
+{
+  AssertMainThread();
+  sSystemClockChangeObservers.RemoveObserver(aObserver);
 }
 
 void
-UnregisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
+NotifySystemClockChange(const int64_t& aClockDeltaMS)
+{
+  sSystemClockChangeObservers.BroadcastInformation(aClockDeltaMS);
+}
+
+class SystemTimezoneChangeObserversManager : public ObserversManager<SystemTimezoneChangeInformation>
+{
+protected:
+  void EnableNotifications() {
+    PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications());
+  }
+
+  void DisableNotifications() {
+    PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications());
+  }
+};
+
+static SystemTimezoneChangeObserversManager sSystemTimezoneChangeObservers;
+
+void
+RegisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
 {
   AssertMainThread();
-  sSystemTimeObservers.RemoveObserver(aObserver);
+  sSystemTimezoneChangeObservers.AddObserver(aObserver);
 }
 
 void
-NotifySystemTimeChange(const hal::SystemTimeChange& aReason)
+UnregisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
 {
-  sSystemTimeObservers.BroadcastInformation(aReason);
+  AssertMainThread();
+  sSystemTimezoneChangeObservers.RemoveObserver(aObserver);
 }
- 
+
+void
+NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+{
+  sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo);
+}
+
 void 
 AdjustSystemClock(int64_t aDeltaMilliseconds)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
 }
 
 void 
@@ -602,18 +636,18 @@ void
 UnregisterWakeLockObserver(WakeLockObserver* aObserver)
 {
   AssertMainThread();
   sWakeLockObservers.RemoveObserver(aObserver);
 }
 
 void
 ModifyWakeLock(const nsAString &aTopic,
-               hal::WakeLockControl aLockAdjust,
-               hal::WakeLockControl aHiddenAdjust)
+               WakeLockControl aLockAdjust,
+               WakeLockControl aHiddenAdjust)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
 }
 
 void
 GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
 {
@@ -666,39 +700,39 @@ LockScreenOrientation(const dom::ScreenO
 void
 UnlockScreenOrientation()
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(UnlockScreenOrientation());
 }
 
 void
-EnableSwitchNotifications(hal::SwitchDevice aDevice) {
+EnableSwitchNotifications(SwitchDevice aDevice) {
   AssertMainThread();
   PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
 }
 
 void
-DisableSwitchNotifications(hal::SwitchDevice aDevice) {
+DisableSwitchNotifications(SwitchDevice aDevice) {
   AssertMainThread();
   PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
 }
 
-hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice)
+SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
 }
 
 typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
 
 static SwitchObserverList *sSwitchObserverLists = NULL;
 
 static SwitchObserverList&
-GetSwitchObserverList(hal::SwitchDevice aDevice) {
+GetSwitchObserverList(SwitchDevice aDevice) {
   MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE); 
   if (sSwitchObserverLists == NULL) {
     sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
   }
   return sSwitchObserverLists[aDevice];
 }
 
 static void
@@ -709,28 +743,28 @@ ReleaseObserversIfNeeded() {
   }
 
   //The length of every list is 0, no observer in the list.
   delete [] sSwitchObserverLists;
   sSwitchObserverLists = NULL;
 }
 
 void
-RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
 {
   AssertMainThread();
   SwitchObserverList& observer = GetSwitchObserverList(aDevice);
   observer.AddObserver(aObserver);
   if (observer.Length() == 1) {
     EnableSwitchNotifications(aDevice);
   }
 }
 
 void
-UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
 {
   AssertMainThread();
 
   if (!sSwitchObserverLists) {
     return;
   }
 
   SwitchObserverList& observer = GetSwitchObserverList(aDevice);
@@ -738,17 +772,17 @@ UnregisterSwitchObserver(hal::SwitchDevi
     return;
   }
 
   DisableSwitchNotifications(aDevice);
   ReleaseObserversIfNeeded();
 }
 
 void
-NotifySwitchChange(const hal::SwitchEvent& aEvent)
+NotifySwitchChange(const SwitchEvent& aEvent)
 {
   // When callback this notification, main thread may call unregister function
   // first. We should check if this pointer is valid.
   if (!sSwitchObserverLists)
     return;
 
   SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
   observer.Broadcast(aEvent);
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -45,17 +45,18 @@ namespace hal {
 typedef Observer<void_t> AlarmObserver;
 typedef Observer<ScreenConfiguration> ScreenConfigurationObserver;
 
 class WindowIdentifier;
 
 extern PRLogModuleInfo *sHalLog;
 #define HAL_LOG(msg) PR_LOG(mozilla::hal::sHalLog, PR_LOG_DEBUG, msg)
 
-typedef Observer<SystemTimeChange> SystemTimeObserver;
+typedef Observer<int64_t> SystemClockChangeObserver;
+typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
 } // namespace hal
 
 namespace MOZ_HAL_NAMESPACE {
 
 /**
  * Turn the default vibrator device on/off per the pattern specified
  * by |pattern|.  Each element in the pattern is the number of
@@ -253,32 +254,55 @@ void SetTimezone(const nsCString& aTimez
 
 /**
  * Get timezone
  * http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  */
 nsCString GetTimezone();
 
 /**
- * Register observer for system time changed notification.
+ * Register observer for system clock changed notification.
  * @param aObserver The observer that should be added.
  */
-void RegisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
+void RegisterSystemClockChangeObserver(
+  hal::SystemClockChangeObserver* aObserver);
+
+/**
+ * Unregister the observer for system clock changed.
+ * @param aObserver The observer that should be removed.
+ */
+void UnregisterSystemClockChangeObserver(
+  hal::SystemClockChangeObserver* aObserver);
+
+/**
+ * Notify of a change in the system clock.
+ * @param aClockDeltaMS
+ */
+void NotifySystemClockChange(const int64_t& aClockDeltaMS);
 
 /**
- * Unregister the observer for system time changed.
+ * Register observer for system timezone changed notification.
+ * @param aObserver The observer that should be added.
+ */
+void RegisterSystemTimezoneChangeObserver(
+  hal::SystemTimezoneChangeObserver* aObserver);
+
+/**
+ * Unregister the observer for system timezone changed.
  * @param aObserver The observer that should be removed.
  */
-void UnregisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
+void UnregisterSystemTimezoneChangeObserver(
+  hal::SystemTimezoneChangeObserver* aObserver);
 
 /**
- * Notify of a change in the system cloeck or time zone.
- * @param aReason
+ * Notify of a change in the system timezone.
+ * @param aSystemTimezoneChangeInfo
  */
-void NotifySystemTimeChange(const hal::SystemTimeChange& aReason);
+void NotifySystemTimezoneChange(
+  const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
 
 /**
  * Reboot the device.
  * 
  * This API is currently only allowed to be used from the main process.
  */
 void Reboot();
 
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -70,22 +70,32 @@ void DisableSwitchNotifications(hal::Swi
 bool EnableAlarm();
 
 /**
  * Disable alarm notifications from the backend.
  */
 void DisableAlarm();
 
 /**
- * Enable system time change notifications from the backend.
+ * Enable system clock change notifications from the backend.
  */
-void EnableSystemTimeChangeNotifications();
+void EnableSystemClockChangeNotifications();
 
 /**
- * Disable system time change notifications from the backend.
+ * Disable system clock change notifications from the backend.
+ */
+void DisableSystemClockChangeNotifications();
+
+/**
+ * Enable system timezone change notifications from the backend.
  */
-void DisableSystemTimeChangeNotifications();
+void EnableSystemTimezoneChangeNotifications();
+
+/**
+ * Disable system timezone change notifications from the backend.
+ */
+void DisableSystemTimezoneChangeNotifications();
 
 bool IsHalChildLive();
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #endif  // mozilla_HalInternal_h
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -79,23 +79,16 @@ enum ProcessPriority {
  */
 enum WakeLockControl {
   WAKE_LOCK_REMOVE_ONE = -1,
   WAKE_LOCK_NO_CHANGE  = 0,
   WAKE_LOCK_ADD_ONE    = 1,
   NUM_WAKE_LOCK
 };
 
-enum SystemTimeChange {
-  SYS_TIME_CHANGE_UNKNOWN = -1,
-  SYS_TIME_CHANGE_CLOCK,
-  SYS_TIME_CHANGE_TZ,
-  SYS_TIME_CHANGE_GUARD
-};
-
 class FMRadioOperationInformation;
 
 enum FMRadioOperation {
   FM_RADIO_OPERATION_UNKNOWN = -1,
   FM_RADIO_OPERATION_ENABLE,
   FM_RADIO_OPERATION_DISABLE,
   FM_RADIO_OPERATION_SEEK,
   NUM_FM_RADIO_OPERATION
@@ -162,17 +155,16 @@ enum FMRadioCountry {
   FM_RADIO_COUNTRY_TW,  //Taiwan
   FM_RADIO_COUNTRY_TR,  //Turkey
   FM_RADIO_COUNTRY_UA,  //Ukraine
   FM_RADIO_COUNTRY_USER_DEFINED,
   NUM_FM_RADIO_COUNTRY
 };
 
 typedef Observer<FMRadioOperationInformation> FMRadioObserver;
-typedef Observer<SystemTimeChange> SystemTimeChangeObserver;
 } // namespace hal
 } // namespace mozilla
 
 namespace IPC {
 
 /**
  * Light type serializer.
  */
@@ -246,26 +238,16 @@ struct ParamTraits<mozilla::hal::SwitchD
 template <>
 struct ParamTraits<mozilla::hal::ProcessPriority>:
   public EnumSerializer<mozilla::hal::ProcessPriority,
                         mozilla::hal::PROCESS_PRIORITY_BACKGROUND,
                         mozilla::hal::NUM_PROCESS_PRIORITY> {
 };
 
 /**
- * SystemTimeChange serializer.
- */
-template <>
-struct ParamTraits<mozilla::hal::SystemTimeChange>
-  : public EnumSerializer<mozilla::hal::SystemTimeChange,
-                          mozilla::hal::SYS_TIME_CHANGE_UNKNOWN,
-                          mozilla::hal::SYS_TIME_CHANGE_GUARD>
-{};
- 
-/**
  * Serializer for FMRadioOperation
  */
 template <>
 struct ParamTraits<mozilla::hal::FMRadioOperation>:
   public EnumSerializer<mozilla::hal::FMRadioOperation,
                         mozilla::hal::FM_RADIO_OPERATION_UNKNOWN,
                         mozilla::hal::NUM_FM_RADIO_OPERATION>
 {};
--- a/hal/fallback/FallbackTime.cpp
+++ b/hal/fallback/FallbackTime.cpp
@@ -20,18 +20,29 @@ SetTimezone(const nsCString& aTimezoneSp
 
 nsCString
 GetTimezone()
 {
   return EmptyCString();
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
+{
+}
+
+void
+DisableSystemClockChangeNotifications()
 {
 }
 
 void
-DisableSystemTimeChangeNotifications()
+EnableSystemTimezoneChangeNotifications()
 {
 }
+
+void
+DisableSystemTimezoneChangeNotifications()
+{
+}
+
 } // namespace hal_impl
 } // namespace mozilla
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -638,48 +638,76 @@ AdjustSystemClock(int64_t aDeltaMillisec
     return;
   }
 
   if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
     HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
     return;
   }
 
-  hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_CLOCK);
+  hal::NotifySystemClockChange(aDeltaMilliseconds);
+}
+
+static int32_t
+GetTimezoneOffset()
+{
+  PRExplodedTime prTime;
+  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
+
+  // Daylight saving time (DST) will be taken into account.
+  int32_t offset = prTime.tm_params.tp_gmt_offset;
+  offset += prTime.tm_params.tp_dst_offset;
+
+  // Returns the timezone offset relative to UTC in minutes.
+  return -(offset / 60);
 }
 
 void
 SetTimezone(const nsCString& aTimezoneSpec)
 {
   if (aTimezoneSpec.Equals(GetTimezone())) {
     return;
   }
 
+  int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset();
   property_set("persist.sys.timezone", aTimezoneSpec.get());
   // this function is automatically called by the other time conversion
   // functions that depend on the timezone. To be safe, we call it manually.
   tzset();
-  hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_TZ);
+  int32_t newTimezoneOffsetMinutes = GetTimezoneOffset();
+  hal::NotifySystemTimezoneChange(
+    hal::SystemTimezoneChangeInformation(
+      oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes));
 }
 
 nsCString
 GetTimezone()
 {
   char timezone[32];
   property_get("persist.sys.timezone", timezone, "");
   return nsCString(timezone);
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
 {
 }
 
 void
-DisableSystemTimeChangeNotifications()
+DisableSystemClockChangeNotifications()
+{
+}
+
+void
+EnableSystemTimezoneChangeNotifications()
+{
+}
+
+void
+DisableSystemTimezoneChangeNotifications()
 {
 }
 
 // Nothing to do here.  Gonk widgetry always listens for screen
 // orientation changes.
 void
 EnableScreenConfigurationNotifications()
 {
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -19,17 +19,16 @@ using mozilla::hal::LightMode;
 using mozilla::hal::SensorType;
 using mozilla::hal::SensorAccuracyType;
 using mozilla::hal::WakeLockControl;
 using mozilla::hal::SwitchState;
 using mozilla::hal::SwitchDevice;
 using mozilla::hal::ProcessPriority;
 using nsIntRect;
 using PRTime;
-using mozilla::hal::SystemTimeChange;
 using mozilla::hal::FMRadioCountry;
 using mozilla::hal::FMRadioOperation;
 using mozilla::hal::FMRadioOperationStatus;
 using mozilla::hal::FMRadioSeekDirection;
 
 namespace mozilla {
 
 namespace hal {
@@ -87,30 +86,38 @@ struct FMRadioOperationInformation {
 struct FMRadioSettings {
   FMRadioCountry country;
   uint32_t upperLimit;
   uint32_t lowerLimit;
   uint32_t spaceType;
   uint32_t preEmphasis;
 };
 
+struct SystemTimezoneChangeInformation {
+  // These timezone offsets are relative to UTC in minutes and
+  // have already taken daylight saving time (DST) into account.
+  int32_t oldTimezoneOffsetMinutes;
+  int32_t newTimezoneOffsetMinutes;
+};
+
 } // namespace hal
 
 namespace hal_sandbox {
 
 sync protocol PHal {
     manager PContent;
 
 child:
     NotifyBatteryChange(BatteryInformation aBatteryInfo);
     NotifyNetworkChange(NetworkInformation aNetworkInfo);
     NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
     NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
     NotifySwitchChange(SwitchEvent aEvent);
-    NotifySystemTimeChange(SystemTimeChange aReason); 
+    NotifySystemClockChange(int64_t aClockDeltaMS); 
+    NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo); 
     NotifyFMRadioStatus(FMRadioOperationInformation aInfo);
 
 parent:
     Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
     CancelVibrate(uint64_t[] id, PBrowser browser);
 
     EnableBatteryNotifications();
     DisableBatteryNotifications();
@@ -130,18 +137,20 @@ parent:
 
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
 
     AdjustSystemClock(int64_t aDeltaMilliseconds);
     SetTimezone(nsCString aTimezoneSpec);
     sync GetTimezone()
       returns (nsCString aTimezoneSpec);
-    EnableSystemTimeChangeNotifications();
-    DisableSystemTimeChangeNotifications();
+    EnableSystemClockChangeNotifications();
+    DisableSystemClockChangeNotifications();
+    EnableSystemTimezoneChangeNotifications();
+    DisableSystemTimezoneChangeNotifications();
 
     sync SetLight(LightType light, LightConfiguration aConfig)
       returns (bool status);
     sync GetLight(LightType light)
       returns (LightConfiguration aConfig, bool status);
 
     ModifyWakeLock(nsString aTopic, WakeLockControl aLockAdjust, WakeLockControl aHiddenAdjust);
     EnableWakeLockNotifications();
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -207,25 +207,37 @@ nsCString
 GetTimezone()
 {
   nsCString timezone;
   Hal()->SendGetTimezone(&timezone);
   return timezone;
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
 {
-  Hal()->SendEnableSystemTimeChangeNotifications();
+  Hal()->SendEnableSystemClockChangeNotifications();
 }
 
 void
-DisableSystemTimeChangeNotifications()
+DisableSystemClockChangeNotifications()
+{
+  Hal()->SendDisableSystemClockChangeNotifications();
+}
+
+void
+EnableSystemTimezoneChangeNotifications()
 {
-  Hal()->SendDisableSystemTimeChangeNotifications();
+  Hal()->SendEnableSystemTimezoneChangeNotifications();
+}
+
+void
+DisableSystemTimezoneChangeNotifications()
+{
+  Hal()->SendDisableSystemTimezoneChangeNotifications();
 }
 
 void
 Reboot()
 {
   NS_RUNTIMEABORT("Reboot() can't be called from sandboxed contexts.");
 }
 
@@ -389,33 +401,35 @@ FactoryReset()
 
 class HalParent : public PHalParent
                 , public BatteryObserver
                 , public NetworkObserver
                 , public ISensorObserver
                 , public WakeLockObserver
                 , public ScreenConfigurationObserver
                 , public SwitchObserver
-                , public SystemTimeObserver
+                , public SystemClockChangeObserver
+                , public SystemTimezoneChangeObserver
 {
 public:
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE
   {
     // NB: you *must* unconditionally unregister your observer here,
     // if it *may* be registered below.
     hal::UnregisterBatteryObserver(this);
     hal::UnregisterNetworkObserver(this);
     hal::UnregisterScreenConfigurationObserver(this);
     for (int32_t sensor = SENSOR_UNKNOWN + 1;
          sensor < NUM_SENSOR_TYPE; ++sensor) {
       hal::UnregisterSensorObserver(SensorType(sensor), this);
     }
     hal::UnregisterWakeLockObserver(this);
-    hal::UnregisterSystemTimeChangeObserver(this);
+    hal::UnregisterSystemClockChangeObserver(this);
+    hal::UnregisterSystemTimezoneChangeObserver(this);
   }
 
   virtual bool
   RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
               const InfallibleTArray<uint64_t> &id,
               PBrowserParent *browserParent) MOZ_OVERRIDE
   {
     // We give all content vibration permission.
@@ -638,26 +652,40 @@ public:
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
     *aTimezoneSpec = hal::GetTimezone();
     return true;
   }
 
   virtual bool
-  RecvEnableSystemTimeChangeNotifications() MOZ_OVERRIDE
+  RecvEnableSystemClockChangeNotifications() MOZ_OVERRIDE
   {
-    hal::RegisterSystemTimeChangeObserver(this);
+    hal::RegisterSystemClockChangeObserver(this);
     return true;
   }
 
   virtual bool
-  RecvDisableSystemTimeChangeNotifications() MOZ_OVERRIDE
+  RecvDisableSystemClockChangeNotifications() MOZ_OVERRIDE
+  {
+    hal::UnregisterSystemClockChangeObserver(this);
+    return true;
+  }
+
+  virtual bool
+  RecvEnableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
   {
-    hal::UnregisterSystemTimeChangeObserver(this);
+    hal::RegisterSystemTimezoneChangeObserver(this);
+    return true;
+  }
+
+  virtual bool
+  RecvDisableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
+  {
+    hal::UnregisterSystemTimezoneChangeObserver(this);
     return true;
   }
 
   virtual bool
   RecvEnableSensorNotifications(const SensorType &aSensor) MOZ_OVERRIDE {
     // We currently allow any content to register device-sensor
     // listeners.
     hal::RegisterSensorObserver(aSensor, this);
@@ -744,19 +772,24 @@ public:
   RecvSetProcessPriority(const int& aPid, const ProcessPriority& aPriority)
   {
     // TODO As a security check, we should ensure that aPid is either the pid
     // of our child, or the pid of one of the child's children.
     hal::SetProcessPriority(aPid, aPriority);
     return true;
   }
 
-  void Notify(const SystemTimeChange& aReason)
+  void Notify(const int64_t& aClockDeltaMS)
   {
-    unused << SendNotifySystemTimeChange(aReason);
+    unused << SendNotifySystemClockChange(aClockDeltaMS);
+  }
+
+  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+  {
+    unused << SendNotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
   }
 
   virtual bool
   RecvEnableFMRadio(const hal::FMRadioSettings& aSettings)
   {
     if (!AssertAppProcessPermission(this, "fmradio")) {
       return false;
     }
@@ -897,18 +930,25 @@ public:
 
   virtual bool
   RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) MOZ_OVERRIDE {
     hal::NotifySwitchChange(aEvent);
     return true;
   }
 
   virtual bool
-  RecvNotifySystemTimeChange(const SystemTimeChange& aReason) {
-    hal::NotifySystemTimeChange(aReason);
+  RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) {
+    hal::NotifySystemClockChange(aClockDeltaMS);
+    return true;
+  }
+
+  virtual bool
+  RecvNotifySystemTimezoneChange(
+    const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) {
+    hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
     return true;
   }
 
   virtual bool
   RecvNotifyFMRadioStatus(const FMRadioOperationInformation& aRadioStatus) {
     hal::NotifyFMRadioStatus(aRadioStatus);
     return true;
   }