← Back to team overview

sikuli-driver team mailing list archive

Re: [Question #286253]: Need a region is quiet (not changing) function

 

Question #286253 on Sikuli changed:
https://answers.launchpad.net/sikuli/+question/286253

    Status: Open => Solved

Spencer Keller confirmed that the question is solved:
Well I wrote it and it works very well.  I now feel like my code is
making a reasonable check to see if the application is done loading
rather than just some arbitrary sleep.  Use it and enjoy and comments
are always welcome.

Spence
-----------------------------------------------------------------------------
To use:

public void waitForQuite(final Region region) {
    QuietHandler observeHandler = new QuietHandler(region);
    region.onChange(observeHandler);
    region.observe();

    if (observeHandler.timedOut() == true) {
        Sysytem.out.println("The QuietHandler timed out.");
        }
    }
-----------------------------------------------------------------------------
package com.solidfire.vat.util;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;

import org.sikuli.basics.Settings;
import org.sikuli.script.ObserveEvent;
import org.sikuli.script.ObserverCallBack;
import org.sikuli.script.Region;

/**
 * A Sikuli ObserverCallBack class that checks to see if a Region has reached a
 * "quiet" state. A "quiet" state being defined as a region that has not changed
 * in a specified amount of time. The amount of time is determined by the
 * checkRate specified at the time of construction. The default value is 2
 * seconds.
 */
public class QuietHandler extends ObserverCallBack {
    static private long _defaultCheckRate = 500;
    static private long _defaultTimeout = 30000;
    static private int _quietCount = 4;

    private Region _watchRegion = null;
    private int _pixelCnt = 0;
    private int _counter = 1;
    private Timer _timer = new Timer();
    private AtomicBoolean _timesUp = new AtomicBoolean(false);
    private AtomicBoolean _regionChanged = new AtomicBoolean(true);

    /**
     * Construct a new QuietHandler for the specified region. Use the default
     * check rate of 1/2 seconds (500 ms) and default time out of 30 seconds
     * (30000 ms).
     * 
     * @param region the region that is being observed for change.
     */
    public QuietHandler(final Region region) {
	this(region, _defaultCheckRate, _defaultTimeout);
    }

    /**
     * Construct a new QuietHandler for the specified region and the specified
     * check rate. Use the default time out of 30 seconds (30000 ms).
     * 
     * @param region the region that is being observed for change.
     * @param checkRate time in milliseconds between checks for region changes.
     */
    public QuietHandler(final Region region, final long checkRate) {
	this(region, checkRate, _defaultTimeout);
    }

    /**
     * Construct a new QuietHandler for the specified region, the specified
     * check rate, and the specified time out.
     * 
     * @param region the region that is being observed for change.
     * @param checkRate time in milliseconds between checks for region changes.
     * @param timeout time in milliseconds when the checks for changes times out and
     *                terminates the observation.
     */
    public QuietHandler(final Region region, final long checkRate, final long timeout) {
	super();
	_watchRegion = region;
	_pixelCnt = Settings.ObserveMinChangedPixels;
	Settings.ObserveMinChangedPixels = 1;

	_timer.scheduleAtFixedRate(getQuietTask(), 0, checkRate);
	_timer.schedule(getTimesUpTask(), timeout);
    }

    @Override
    public void changed(final ObserveEvent event) {
	_regionChanged.set(true);
    }

    /**
     * Did the observed region reach a "quiet" state or did it time out. A
     * "quiet" state is defined as a region that has not changed in a specified
     * amount of time. The amount of time is determined by the checkRate
     * specified at the time of construction. The default value is 2 seconds.
     * 
     * @return false if the region reached the quiet state, true if not.
     */
    public boolean timedOut() {
	return _timesUp.get();
    }

    /*
     * Return a timer task that sets the "times up" flag to true.
     */
    private TimerTask getTimesUpTask() {
	return new TimerTask() {
	    public void run() {
		_timesUp.set(true);
	    }
	};
    }

    /*
     * Return a timer task that checks to see if the observed region has changed
     * since it was last called. If the region has changed, a "quiet counter" is
     * set to 1, its' starting value. However if it has not changed the
     * "quiet counter" is incremented by one and if it reaches 4, all timer
     * tasks are cancelled, the regions observer is stopped and the region is
     * deemed to be "quiet". The task also checks to see if a timeout has
     * occurred in which case everything is shut down ending the observation.
     */
    private TimerTask getQuietTask() {
	return new TimerTask() {
	    public void run() {
		// Is time up?
		if (_timesUp.get() == true) {
		    cleanUp();
		    return;
		}

		// Reset the change flag to false then see if the region changed
		// since we were last called?
		// If not increment the counter else reset the counter to 1.
		if (_regionChanged.getAndSet(false) == false) {
		    _counter++;
		} else {
		    _counter = 1;
		}

		if (_counter >= _quietCount) {
		    cleanUp();
		}
	    }
	};
    }

    /*
     * Cancel both of the timer tasks, reset the ObserveMinChangedPixels, and
     * tell the region to stop the observer.
     */
    private void cleanUp() {
	_timer.cancel();
	_timer.purge();
	Settings.ObserveMinChangedPixels = _pixelCnt;
	_watchRegion.stopObserver();
    }
}

-- 
You received this question notification because your team Sikuli Drivers
is an answer contact for Sikuli.