Application Idle Time

Application idle time

I would be doing it in this way:

  1. Create thread which will control idle activity
  2. Run this thread in Application environment
  3. At each user interaction just refresh idle time

Class for storing global Thread which will control idle time

public class ControlApplication extends Application
{
private static final String TAG=ControlApplication.class.getName();
private Waiter waiter; //Thread which controls idle time

// only lazy initializations here!
@Override
public void onCreate()
{
super.onCreate();
Log.d(TAG, "Starting application"+this.toString());
waiter=new Waiter(15*60*1000); //15 mins
waiter.start();
}

public void touch()
{
waiter.touch();
}
}

Class which will be parent for all of your activities

public class ControlActivity extends Activity
{
private static final String TAG=ControlActivity.class.getName();

/**
* Gets reference to global Application
* @return must always be type of ControlApplication! See AndroidManifest.xml
*/
public ControlApplication getApp()
{
return (ControlApplication )this.getApplication();
}

@Override
public void onUserInteraction()
{
super.onUserInteraction();
getApp().touch();
Log.d(TAG, "User interaction to "+this.toString());
}

}

And finally Thread itself

public class Waiter extends Thread
{
private static final String TAG=Waiter.class.getName();
private long lastUsed;
private long period;
private boolean stop;

public Waiter(long period)
{
this.period=period;
stop=false;
}

public void run()
{
long idle=0;
this.touch();
do
{
idle=System.currentTimeMillis()-lastUsed;
Log.d(TAG, "Application is idle for "+idle +" ms");
try
{
Thread.sleep(5000); //check every 5 seconds
}
catch (InterruptedException e)
{
Log.d(TAG, "Waiter interrupted!");
}
if(idle > period)
{
idle=0;
//do something here - e.g. call popup or so
}
}
while(!stop);
Log.d(TAG, "Finishing Waiter thread");
}

public synchronized void touch()
{
lastUsed=System.currentTimeMillis();
}

public synchronized void forceInterrupt()
{
this.interrupt();
}

//soft stopping of thread
public synchronized void stop()
{
stop=true;
}

public synchronized void setPeriod(long period)
{
this.period=period;
}

}

What is the best way to implement idle time out for web application (auto log off)

If I understand your question right, it is not possible, since there are no events triggered in javascript for activity outside of the current window/tab.

Unless you have a addon to go along with your website for each browser, which could monitor all activity in the browser, but that is not really a practical approach.

IIS: Idle Timeout vs Recycle

Idle Timeout is if no action has been asked from your web app, it the process will drop and release everything from memory

Recycle is a forced action on the application where your processed is closed and started again, for memory leaking purposes and system health

The negative impact of both is usually the use of your Session and Application state is lost if you mess with Recycle to a faster time.(logged in users etc will be logged out, if they where about to "check out" all would have been lost" that's why recycle is at such a large time out value, idle timeout doesn't matter because nobody is logged in anyway and figure 20 minutes an no action they are not still "shopping"

The positive would be get rid of the idle time out as your website will respond faster on its "first" response if its not a highly active site where a user would have to wait for it to load if you have 1 user every 20 minutes lets say. So a website that get his less then 1 time in 20 minutes actually you would want to increase this value as the website has to load up again from scratch for each user. but if you set this to 0 over a long time, any memory leaks in code could over a certain amount of time, entirely take over the server.

VB.NET: Idle Time external Application

You can combine GetForgroundWindow and GetLastInputInfo (Win32 functions) in a reasonable loop.

If the target application (target) is running, and the target is not the foreground window then we can assume that the application is idle. Just record the time it transitioned from foreground to background.

If the target is the foreground window then you can use GetLastInputInfo to determine the last time the application received mouse or keyboard input.

** Unfortunately MSDN is down right now so I can't link to the documentation.

How to detect a Winforms app has been idle for certain amount of time

There are many ways to do it and the answer somewhat depends on what you need to do. You are clear and specific about what you need. The following is something I developed that probably would fit your requirements. What it is doing is using Application.Idle to determine when the application has finished processing messages then it sets a timer and filters (listens to) all messages for the application and if a relevant message (such as mouse or keyboard) is received then it resets the timer. It ignores mouse move since it is possible to move the mouse over the application without using the application. It has been a while since I wrote that so I am not sure of the details but I could figure it out if necessary. Note that this is a console program to make the sample easier to try but the code is intended for a forms application.

using System;
using System.Security.Permissions;
using System.Windows.Forms;

namespace _121414
{
static class Program
{
public static Timer IdleTimer = new Timer();
const int MinuteMicroseconds = 60000;
static Form1 f = null;

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
LeaveIdleMessageFilter limf = new LeaveIdleMessageFilter();
Application.AddMessageFilter(limf);
Application.Idle += new EventHandler(Application_Idle);
IdleTimer.Interval = MinuteMicroseconds; // One minute; change as needed
IdleTimer.Tick += TimeDone;
IdleTimer.Start();
f = new Form1();
Application.Run(f);
Application.Idle -= new EventHandler(Application_Idle);
}

static private void Application_Idle(Object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}

static private void TimeDone(object sender, EventArgs e)
{
IdleTimer.Stop(); // not really necessary
MessageBox.Show("Auto logoff");
f.Close();
}

}

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public class LeaveIdleMessageFilter : IMessageFilter
{
const int WM_NCLBUTTONDOWN = 0x00A1;
const int WM_NCLBUTTONUP = 0x00A2;
const int WM_NCRBUTTONDOWN = 0x00A4;
const int WM_NCRBUTTONUP = 0x00A5;
const int WM_NCMBUTTONDOWN = 0x00A7;
const int WM_NCMBUTTONUP = 0x00A8;
const int WM_NCXBUTTONDOWN = 0x00AB;
const int WM_NCXBUTTONUP = 0x00AC;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_MOUSEMOVE = 0x0200;
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_RBUTTONDOWN = 0x0204;
const int WM_RBUTTONUP = 0x0205;
const int WM_MBUTTONDOWN = 0x0207;
const int WM_MBUTTONUP = 0x0208;
const int WM_XBUTTONDOWN = 0x020B;
const int WM_XBUTTONUP = 0x020C;

// The Messages array must be sorted due to use of Array.BinarySearch
static int[] Messages = new int[] {WM_NCLBUTTONDOWN,
WM_NCLBUTTONUP, WM_NCRBUTTONDOWN, WM_NCRBUTTONUP, WM_NCMBUTTONDOWN,
WM_NCMBUTTONUP, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, WM_KEYDOWN, WM_KEYUP,
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONDOWN, WM_RBUTTONUP,
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_XBUTTONDOWN, WM_XBUTTONUP};

public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE) // mouse move is high volume
return false;
if (!Program.IdleTimer.Enabled) // idling?
return false; // No
if (Array.BinarySearch(Messages, m.Msg) >= 0)
Program.IdleTimer.Stop();
return false;
}
}
}

Timer based idle time tracking in an application

I should think a network policy to lock the desktop after a perips of inactivity would be the simplest: no need to save any data (as per a previous question).

Since you are emulating the Windows job of tracking the idle time, you could use the API to get the idle time:

Partial Friend Class NativeMethods
<StructLayout(LayoutKind.Sequential)>
Structure LASTINPUTINFO
<MarshalAs(UnmanagedType.U4)>
Public cbSize As Integer
<MarshalAs(UnmanagedType.U4)>
Public dwTime As Integer
End Structure

' Gets the time of the last user input in ms
<DllImport("user32.dll")>
Private Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
End Function

Friend Shared Function GetLastInputTimeElapsed() As Int32
Dim lastInputInf As New LASTINPUTINFO()
lastInputInf.cbSize = Marshal.SizeOf(lastInputInf)
lastInputInf.dwTime = 0

' get time of last input, subtract current ticks
If GetLastInputInfo(lastInputInf) Then
' conver to seconds
Return (Environment.TickCount - lastInputInf.dwTime) \ 1000
Else
Return 0
End If
End Function
...

Then just check the elapsed seconds (or minutes) in a long timer:

Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick

' Gets the time of the last user input in ms
Dim elapsed = NativeMethods.GetLastInputTimeElapsed()

' 45 sec TimeOut for testing
If elapsed > 45 Then
Label3.Text = "You're done!"
Else
Label3.Text = String.Format("Idle for: {0} secs", elapsed)
End If
End Sub

Animated GIFs dont run fast enough to show, but input is detected in the form of any mousemove or keypress. Note that this detects system input - mouse moves and key pressed with your app minimized will count. This makes some sense - if the app is minimized and times itself out, I'd be suprised to see it just disappear. If I am totally AFK, thats another thing.


Local Timer

For a simple form, the answer for VB Detect Idle time is pretty simple: it stops and restarts your 30 min timer whenever it sees a mousemove or keypress. It doesnt detect movement on container controls though.

Using a Stopwatch will work too:

' form/class level
Private swLogout As Stopwatch

' start it with the app:
swLogout = New Stopwatch()
swLogout.Start()

You need to restart it for each keypress and mousemove. For the first, set KeyPreview to true, then:

Private Sub MainFrm_KeyPress(sender As Object, 
e As KeyPressEventArgs) Handles MyBase.KeyPress
swLogout.Restart()
End Sub

Mousemove is more problematic, you need to hook up all the major container controls:

Private Sub MainFrm_MouseMove(sender As Object, 
e As MouseEventArgs) Handles MyBase.MouseMove,
TabControl1.MouseMove, TabControl2.MouseMove,
..., TabPage12.MouseMove
swLogout.Restart()
End Sub

Then check the elapsed time in a fairly short timer (like 3 mins maybe):

Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
Dim elapsed = swLogout.ElapsedMilliseconds \ 1000

' demo == 3 secs
If elapsed > 3 Then
Label3.Text = "You're done!"
Timer2.Enabled = False
Else
Label3.Text = String.Format("Idle for: {0} secs", elapsed)
End If
End Sub


Related Topics



Leave a reply



Submit