1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #ifndef nsIdleService_h__
9 #define nsIdleService_h__
10 
11 #include "nsIIdleServiceInternal.h"
12 #include "nsCOMPtr.h"
13 #include "nsITimer.h"
14 #include "nsTArray.h"
15 #include "nsIObserver.h"
16 #include "nsIIdleService.h"
17 #include "nsCategoryCache.h"
18 #include "nsWeakReference.h"
19 #include "mozilla/TimeStamp.h"
20 
21 /**
22  * Class we can use to store an observer with its associated idle time
23  * requirement and whether or not the observer thinks it's "idle".
24  */
25 class IdleListener {
26  public:
27   nsCOMPtr<nsIObserver> observer;
28   uint32_t reqIdleTime;
29   bool isIdle;
30 
31   IdleListener(nsIObserver* obs, uint32_t reqIT, bool aIsIdle = false)
observer(obs)32       : observer(obs), reqIdleTime(reqIT), isIdle(aIsIdle) {}
33   ~IdleListener() = default;
34 };
35 
36 // This one will be declared later.
37 class nsIdleService;
38 
39 /**
40  * Class to handle the daily idle timer.
41  */
42 class nsIdleServiceDaily : public nsIObserver, public nsSupportsWeakReference {
43  public:
44   NS_DECL_ISUPPORTS
45   NS_DECL_NSIOBSERVER
46 
47   explicit nsIdleServiceDaily(nsIIdleService* aIdleService);
48 
49   /**
50    * Initializes the daily idle observer.
51    * Keep this separated from the constructor, since it could cause pointer
52    * corruption due to AddRef/Release of "this".
53    */
54   void Init();
55 
56  private:
57   virtual ~nsIdleServiceDaily();
58 
59   /**
60    * StageIdleDaily is the interim call made when an idle-daily event is due.
61    * However we don't want to fire idle-daily until the user is idle for this
62    * session, so this sets up a short wait for an idle event which triggers
63    * the actual idle-daily event.
64    *
65    * @param aHasBeenLongWait Pass true indicating nsIdleServiceDaily is having
66    * trouble getting the idle-daily event fired. If true StageIdleDaily will
67    * use a shorter idle wait time before firing idle-daily.
68    */
69   void StageIdleDaily(bool aHasBeenLongWait);
70 
71   /**
72    * @note This is a normal pointer, part to avoid creating a cycle with the
73    * idle service, part to avoid potential pointer corruption due to this class
74    * being instantiated in the constructor of the service itself.
75    */
76   nsIIdleService* mIdleService;
77 
78   /**
79    * Place to hold the timer used by this class to determine when a day has
80    * passed, after that it will wait for idle time to be detected.
81    */
82   nsCOMPtr<nsITimer> mTimer;
83 
84   /**
85    * Function that is called back once a day.
86    */
87   static void DailyCallback(nsITimer* aTimer, void* aClosure);
88 
89   /**
90    * Cache of observers for the "idle-daily" category.
91    */
92   nsCategoryCache<nsIObserver> mCategoryObservers;
93 
94   /**
95    * Boolean set to true when daily idle notifications should be disabled.
96    */
97   bool mShutdownInProgress;
98 
99   /**
100    * Next time we expect an idle-daily timer to fire, in case timers aren't
101    * very reliable on the platform. Value is in PR_Now microsecond units.
102    */
103   PRTime mExpectedTriggerTime;
104 
105   /**
106    * Tracks which idle daily observer callback we ask for. There are two: a
107    * regular long idle wait and a shorter wait if we've been waiting to fire
108    * idle daily for an extended period. Set by StageIdleDaily.
109    */
110   int32_t mIdleDailyTriggerWait;
111 };
112 
113 class nsIdleService : public nsIIdleServiceInternal {
114  public:
115   NS_DECL_ISUPPORTS
116   NS_DECL_NSIIDLESERVICE
117   NS_DECL_NSIIDLESERVICEINTERNAL
118 
119  protected:
120   static already_AddRefed<nsIdleService> GetInstance();
121 
122   nsIdleService();
123   virtual ~nsIdleService();
124 
125   /**
126    * If there is a platform specific function to poll the system idel time
127    * then that must be returned in this function, and the function MUST return
128    * true, otherwise then the function should be left unimplemented or made
129    * to return false (this can also be used for systems where it depends on
130    * the configuration of the system if the idle time can be determined)
131    *
132    * @param aIdleTime
133    *        The idle time in ms.
134    *
135    * @return true if the idle time could be polled, false otherwise.
136    *
137    * @note The time returned by this function can be different than the one
138    *       returned by GetIdleTime, as that is corrected by any calls to
139    *       ResetIdleTimeOut(), unless you overwrite that function too...
140    */
141   virtual bool PollIdleTime(uint32_t* aIdleTime);
142 
143   /**
144    * Function that determines if we are in poll mode or not.
145    *
146    * @return true if polling is supported, false otherwise.
147    */
148   virtual bool UsePollMode();
149 
150  private:
151   /**
152    * Ensure that the timer is expiring at least at the given time
153    *
154    * The function might not restart the timer if there is one running currently
155    *
156    * @param aNextTimeout
157    *        The last absolute time the timer should expire
158    */
159   void SetTimerExpiryIfBefore(mozilla::TimeStamp aNextTimeout);
160 
161   /**
162    * Stores the next timeout time, 0 means timer not running
163    */
164   mozilla::TimeStamp mCurrentlySetToTimeoutAt;
165 
166   /**
167    * mTimer holds the internal timer used by this class to detect when to poll
168    * for idle time, when to check if idle timers should expire etc.
169    */
170   nsCOMPtr<nsITimer> mTimer;
171 
172   /**
173    * Array of listeners that wants to be notified about idle time.
174    */
175   nsTArray<IdleListener> mArrayListeners;
176 
177   /**
178    * Object keeping track of the daily idle thingy.
179    */
180   RefPtr<nsIdleServiceDaily> mDailyIdle;
181 
182   /**
183    * Number of observers currently in idle mode.
184    */
185   uint32_t mIdleObserverCount;
186 
187   /**
188    * Delta time from last non idle time to when the next observer should switch
189    * to idle mode
190    *
191    * Time in seconds
192    *
193    * If this value is 0 it means there are no active observers
194    */
195   uint32_t mDeltaToNextIdleSwitchInS;
196 
197   /**
198    * If true, the idle service is temporarily disabled, and all idle events
199    * will be ignored.
200    */
201   bool mDisabled = false;
202 
203   /**
204    * Absolute value for when the last user interaction took place.
205    */
206   mozilla::TimeStamp mLastUserInteraction;
207 
208   /**
209    * Function that ensures the timer is running with at least the minimum time
210    * needed.  It will kill the timer if there are no active observers.
211    */
212   void ReconfigureTimer(void);
213 
214   /**
215    * Callback function that is called when the internal timer expires.
216    *
217    * This in turn calls the IdleTimerCallback that does the real processing
218    */
219   static void StaticIdleTimerCallback(nsITimer* aTimer, void* aClosure);
220 
221   /**
222    * Function that handles when a timer has expired
223    */
224   void IdleTimerCallback(void);
225 };
226 
227 #endif  // nsIdleService_h__
228