Bug 801096 - [settings] Set-Automatically for time should take effect *immediately* instead of waiting on next NITZ coming (part 1). r=jlebar, a=blocking-basecamp
authorGene Lian <clian@mozilla.com>
Tue, 23 Oct 2012 15:15:43 +0800
changeset 116309 6bf509795bc838093386eb2925d573319ada408e
parent 116308 58ba9dc8ea5a659936ab1e5c66728a862cd31887
child 116310 597e5d695e469bf4c356880bc7639966e0672001
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar, blocking-basecamp
bugs801096
milestone18.0a2
Bug 801096 - [settings] Set-Automatically for time should take effect *immediately* instead of waiting on next NITZ coming (part 1). r=jlebar, a=blocking-basecamp
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;
   }