idletimer.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Idle Timer.
  16. *
  17. * Keeps track of transitions between active and idle. This class is built on
  18. * top of ActivityMonitor. Whenever an active user becomes idle, this class
  19. * dispatches a BECOME_IDLE event. Whenever an idle user becomes active, this
  20. * class dispatches a BECOME_ACTIVE event. The amount of inactive time it
  21. * takes for a user to be considered idle is specified by the client, and
  22. * different instances of this class can all use different thresholds.
  23. *
  24. */
  25. goog.provide('goog.ui.IdleTimer');
  26. goog.require('goog.Timer');
  27. goog.require('goog.events');
  28. goog.require('goog.events.EventTarget');
  29. goog.require('goog.structs.Set');
  30. goog.require('goog.ui.ActivityMonitor');
  31. /**
  32. * Event target that will give notification of state changes between active and
  33. * idle. This class is designed to require few resources while the user is
  34. * active.
  35. * @param {number} idleThreshold Amount of time in ms at which we consider the
  36. * user has gone idle.
  37. * @param {goog.ui.ActivityMonitor=} opt_activityMonitor The activity monitor
  38. * keeping track of user interaction. Defaults to a default-constructed
  39. * activity monitor. If a default activity monitor is used then this class
  40. * will dispose of it. If an activity monitor is passed in then the caller
  41. * remains responsible for disposing of it.
  42. * @constructor
  43. * @extends {goog.events.EventTarget}
  44. * @final
  45. */
  46. goog.ui.IdleTimer = function(idleThreshold, opt_activityMonitor) {
  47. goog.events.EventTarget.call(this);
  48. var activityMonitor =
  49. opt_activityMonitor || this.getDefaultActivityMonitor_();
  50. /**
  51. * The amount of time in ms at which we consider the user has gone idle
  52. * @type {number}
  53. * @private
  54. */
  55. this.idleThreshold_ = idleThreshold;
  56. /**
  57. * The activity monitor keeping track of user interaction
  58. * @type {goog.ui.ActivityMonitor}
  59. * @private
  60. */
  61. this.activityMonitor_ = activityMonitor;
  62. /**
  63. * Cached onActivityTick_ bound to the object for later use
  64. * @type {Function}
  65. * @private
  66. */
  67. this.boundOnActivityTick_ = goog.bind(this.onActivityTick_, this);
  68. // Decide whether the user is currently active or idle. This method will
  69. // check whether it is correct to start with the user in the active state.
  70. this.maybeStillActive_();
  71. };
  72. goog.inherits(goog.ui.IdleTimer, goog.events.EventTarget);
  73. /**
  74. * Whether a listener is currently registered for an idle timer event. On
  75. * initialization, the user is assumed to be active.
  76. * @type {boolean}
  77. * @private
  78. */
  79. goog.ui.IdleTimer.prototype.hasActivityListener_ = false;
  80. /**
  81. * Handle to the timer ID used for checking ongoing activity, or null
  82. * @type {?number}
  83. * @private
  84. */
  85. goog.ui.IdleTimer.prototype.onActivityTimerId_ = null;
  86. /**
  87. * Whether the user is currently idle
  88. * @type {boolean}
  89. * @private
  90. */
  91. goog.ui.IdleTimer.prototype.isIdle_ = false;
  92. /**
  93. * The default activity monitor created by this class, if any
  94. * @type {goog.ui.ActivityMonitor?}
  95. * @private
  96. */
  97. goog.ui.IdleTimer.defaultActivityMonitor_ = null;
  98. /**
  99. * The idle timers that currently reference the default activity monitor
  100. * @type {goog.structs.Set}
  101. * @private
  102. */
  103. goog.ui.IdleTimer.defaultActivityMonitorReferences_ = new goog.structs.Set();
  104. /**
  105. * Event constants for the idle timer event target
  106. * @enum {string}
  107. */
  108. goog.ui.IdleTimer.Event = {
  109. /** Event fired when an idle user transitions into the active state */
  110. BECOME_ACTIVE: 'active',
  111. /** Event fired when an active user transitions into the idle state */
  112. BECOME_IDLE: 'idle'
  113. };
  114. /**
  115. * Gets the default activity monitor used by this class. If a default has not
  116. * been created yet, then a new one will be created.
  117. * @return {!goog.ui.ActivityMonitor} The default activity monitor.
  118. * @private
  119. */
  120. goog.ui.IdleTimer.prototype.getDefaultActivityMonitor_ = function() {
  121. goog.ui.IdleTimer.defaultActivityMonitorReferences_.add(this);
  122. if (goog.ui.IdleTimer.defaultActivityMonitor_ == null) {
  123. goog.ui.IdleTimer.defaultActivityMonitor_ = new goog.ui.ActivityMonitor();
  124. }
  125. return goog.ui.IdleTimer.defaultActivityMonitor_;
  126. };
  127. /**
  128. * Removes the reference to the default activity monitor. If there are no more
  129. * references then the default activity monitor gets disposed.
  130. * @private
  131. */
  132. goog.ui.IdleTimer.prototype.maybeDisposeDefaultActivityMonitor_ = function() {
  133. goog.ui.IdleTimer.defaultActivityMonitorReferences_.remove(this);
  134. if (goog.ui.IdleTimer.defaultActivityMonitor_ != null &&
  135. goog.ui.IdleTimer.defaultActivityMonitorReferences_.isEmpty()) {
  136. goog.ui.IdleTimer.defaultActivityMonitor_.dispose();
  137. goog.ui.IdleTimer.defaultActivityMonitor_ = null;
  138. }
  139. };
  140. /**
  141. * Checks whether the user is active. If the user is still active, then a timer
  142. * is started to check again later.
  143. * @private
  144. */
  145. goog.ui.IdleTimer.prototype.maybeStillActive_ = function() {
  146. // See how long before the user would go idle. The user is considered idle
  147. // after the idle time has passed, not exactly when the idle time arrives.
  148. var remainingIdleThreshold = this.idleThreshold_ + 1 -
  149. (goog.now() - this.activityMonitor_.getLastEventTime());
  150. if (remainingIdleThreshold > 0) {
  151. // The user is still active. Check again later.
  152. this.onActivityTimerId_ =
  153. goog.Timer.callOnce(this.boundOnActivityTick_, remainingIdleThreshold);
  154. } else {
  155. // The user has not been active recently.
  156. this.becomeIdle_();
  157. }
  158. };
  159. /**
  160. * Handler for the timeout used for checking ongoing activity
  161. * @private
  162. */
  163. goog.ui.IdleTimer.prototype.onActivityTick_ = function() {
  164. // The timer has fired.
  165. this.onActivityTimerId_ = null;
  166. // The maybeStillActive method will restart the timer, if appropriate.
  167. this.maybeStillActive_();
  168. };
  169. /**
  170. * Transitions from the active state to the idle state
  171. * @private
  172. */
  173. goog.ui.IdleTimer.prototype.becomeIdle_ = function() {
  174. this.isIdle_ = true;
  175. // The idle timer will send notification when the user does something
  176. // interactive.
  177. goog.events.listen(
  178. this.activityMonitor_, goog.ui.ActivityMonitor.Event.ACTIVITY,
  179. this.onActivity_, false, this);
  180. this.hasActivityListener_ = true;
  181. // Notify clients of the state change.
  182. this.dispatchEvent(goog.ui.IdleTimer.Event.BECOME_IDLE);
  183. };
  184. /**
  185. * Handler for idle timer events when the user does something interactive
  186. * @param {goog.events.Event} e The event object.
  187. * @private
  188. */
  189. goog.ui.IdleTimer.prototype.onActivity_ = function(e) {
  190. this.becomeActive_();
  191. };
  192. /**
  193. * Transitions from the idle state to the active state
  194. * @private
  195. */
  196. goog.ui.IdleTimer.prototype.becomeActive_ = function() {
  197. this.isIdle_ = false;
  198. // Stop listening to every interactive event.
  199. this.removeActivityListener_();
  200. // Notify clients of the state change.
  201. this.dispatchEvent(goog.ui.IdleTimer.Event.BECOME_ACTIVE);
  202. // Periodically check whether the user has gone inactive.
  203. this.maybeStillActive_();
  204. };
  205. /**
  206. * Removes the activity listener, if necessary
  207. * @private
  208. */
  209. goog.ui.IdleTimer.prototype.removeActivityListener_ = function() {
  210. if (this.hasActivityListener_) {
  211. goog.events.unlisten(
  212. this.activityMonitor_, goog.ui.ActivityMonitor.Event.ACTIVITY,
  213. this.onActivity_, false, this);
  214. this.hasActivityListener_ = false;
  215. }
  216. };
  217. /** @override */
  218. goog.ui.IdleTimer.prototype.disposeInternal = function() {
  219. this.removeActivityListener_();
  220. if (this.onActivityTimerId_ != null) {
  221. goog.global.clearTimeout(this.onActivityTimerId_);
  222. this.onActivityTimerId_ = null;
  223. }
  224. this.maybeDisposeDefaultActivityMonitor_();
  225. goog.ui.IdleTimer.superClass_.disposeInternal.call(this);
  226. };
  227. /**
  228. * @return {number} the amount of time at which we consider the user has gone
  229. * idle in ms.
  230. */
  231. goog.ui.IdleTimer.prototype.getIdleThreshold = function() {
  232. return this.idleThreshold_;
  233. };
  234. /**
  235. * @return {goog.ui.ActivityMonitor} the activity monitor keeping track of user
  236. * interaction.
  237. */
  238. goog.ui.IdleTimer.prototype.getActivityMonitor = function() {
  239. return this.activityMonitor_;
  240. };
  241. /**
  242. * Returns true if there has been no user action for at least the specified
  243. * interval, and false otherwise
  244. * @return {boolean} true if the user is idle, false otherwise.
  245. */
  246. goog.ui.IdleTimer.prototype.isIdle = function() {
  247. return this.isIdle_;
  248. };