package com.appdivision.manager.idlemanager
{
import com.appdivision.manager.idlemanager.event.IdleEvent;
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.managers.ISystemManager;
[Event(name="unidle", type="com.appdivision.manager.idlemanager.event.IdleEvent")]
[Mixin]
public class IdleManager extends EventDispatcher
{
private static var _instance:IdleManager;
private static var systemManager:ISystemManager;
private var idleCollection:ArrayCollection;
private var timeStamp:Number = 0;
private var idleMilliseconds:Number = 0;
private var idle:Boolean = false;
public function IdleManager(singletonEnforcer:SingletonEnforcer)
{
if (singletonEnforcer == null) {
throw new Error("IdleManager is a singleton class, use getInstance() instead");
}
_instance = this;
idleCollection = new ArrayCollection();
addEventListeners();
}
public static function getInstance():IdleManager{
if (_instance == null)_instance = new IdleManager(new SingletonEnforcer());
return _instance;
}
/**
* called due to the fact that i've used the [Mixin] metatag
* makes sure event listeners have been added to the system manager even if the user doesnt
* @param systemManager
*
*/
public static function init (systemManager:ISystemManager):void{
IdleManager.systemManager = systemManager;
}
private function addEventListeners():void{
systemManager.addEventListener(FlexEvent.IDLE, onIdle);
systemManager.addEventListener(MouseEvent.MOUSE_MOVE, onMouse);
systemManager.addEventListener(MouseEvent.MOUSE_DOWN, onMouse);
systemManager.addEventListener(KeyboardEvent.KEY_DOWN, onKeyboard, true);
}
private function onMouse(e:MouseEvent):void{
if(idle)dispatchEvent(new IdleEvent(IdleEvent.UNIDLE, 0));
idle = false;
}
private function onKeyboard(e:KeyboardEvent):void{
if(idle)dispatchEvent(new IdleEvent(IdleEvent.UNIDLE, 0));
idle = false;
}
/**
* Happens when the application begins idling
* @param e
*
*/
private function onIdle(e:FlexEvent):void{
idle = true;
idleMilliseconds += 100;
var d:Date = new Date();
var curr:Number = Date.UTC(d.getFullYear(), d.month, d.date, d.hours, d.minutes, d.seconds, d.milliseconds);
if(curr > timeStamp + 200)idleMilliseconds = 1000;
timeStamp = curr;
for(var i:Number = 0; i < idleCollection.length; i ++){
var obj:Object = idleCollection.getItemAt(i);
if(idleMilliseconds % obj.milliseconds == 0){
if(obj.isOneTime){
var evt:IdleEvent = new IdleEvent(IdleEvent.ONE_TIME_IDLE, idleMilliseconds);
evt.data = obj.data;
obj.listener( evt );
removeIdleListener(obj.milliseconds, obj.listener);
}else
if(obj.isFirstTime){
if(obj.milliseconds == idleMilliseconds){
var evt:IdleEvent = new IdleEvent(IdleEvent.FIRST_TIME_IDLE, idleMilliseconds);
evt.data = obj.data;
obj.listener( evt );
}
}else
{
var evt:IdleEvent = new IdleEvent(IdleEvent.RECURRING_IDLE, idleMilliseconds);
evt.data = obj.data;
obj.listener( evt );
}
}
}
}
private function checkForExistence(milliseconds:Number, listener:Function, isOneTime:Boolean = false, isFirstTime:Boolean = false):Boolean{
for(var i:Number = 0; i < idleCollection.length; i ++){
var obj:Object = idleCollection.getItemAt(i);
if(obj.milliseconds == milliseconds && obj.listener == listener && obj.isOneTime == isOneTime && obj.isFirstTime == isFirstTime){
return true;
}
}
return false;
}
/**
* Removes an idle listener
* @param milliseconds
* @param listener
*
*/
public function removeIdleListener(milliseconds:Number, listener:Function):void{
for(var i:Number = 0; i < idleCollection.length; i ++){
var obj:Object = idleCollection.getItemAt(i);
if(obj.milliseconds == milliseconds && obj.listener == listener){
idleCollection.removeItemAt(i);
}
}
}
/**
* Will add an event that will be fired recurringly every N number of millseconds when an app is idle
* @param milliseconds Will be rounded to the nearest 100 millisecond
* @param listener listener function to be called with event
* @param data optional data argument to be passed with event
*
*/
public function addRecurringIdleEventListener(milliseconds:Number, listener:Function, data:Object = null):void{
milliseconds = milliseconds < 100 ? 100 : Math.round(milliseconds/100) * 100;
if(checkForExistence(milliseconds, listener, false, false))throw new Error("A listener for this exact time and function have already been added");
var obj:Object = new Object();
obj.milliseconds = milliseconds;
obj.listener = listener;
obj.data = data;
idleCollection.addItem(obj);
}
/**
* Will add an event that will be fired one time the next time the application goes idle and reaches that number of milliseconds - then deletes it
* @param milliseconds Will be rounded to the nearest 100 millisecond
* @param listener listener function to be called with event
* @param data optional data argument to be passed with event
*
*/
public function addOneTimeIdleEventListener(milliseconds:Number, listener:Function, data:Object = null):void{
milliseconds = milliseconds < 100 ? 100 : Math.round(milliseconds/100) * 100;
if(checkForExistence(milliseconds, listener, true, false))throw new Error("A listener for this exact time and function have already been added");
var obj:Object = new Object();
obj.isOneTime = true;
obj.milliseconds = milliseconds;
obj.listener = listener;
obj.data = data;
idleCollection.addItem(obj);
}
/**
* Will add an event that will be fired one time every time the application goes idle and reaches that number of milliseconds
* @param milliseconds Will be rounded to the nearest 100 millisecond
* @param listener listener function to be called with event
* @param data optional data argument to be passed with event
*
*/
public function addFirstTimeIdleEventListener(milliseconds:Number, listener:Function, data:Object = null):void{
milliseconds = milliseconds < 100 ? 100 : Math.round(milliseconds/100) * 100;
if(checkForExistence(milliseconds, listener, false, true))throw new Error("A listener for this exact time and function have already been added");
var obj:Object = new Object();
obj.isFirstTime = true;
obj.milliseconds = milliseconds;
obj.listener = listener;
obj.data = data;
idleCollection.addItem(obj);
}
}
}
/**
* SingletonEnforcer enables access of a Singleton class to be
* restricted to internal
*/
class SingletonEnforcer {}