FileDocCategorySizeDatePackage
MonkeySourceRandom.javaAPI DocAndroid 1.5 API16158Wed May 06 22:41:08 BST 2009com.android.commands.monkey

MonkeySourceRandom

public class MonkeySourceRandom extends Object implements MonkeyEventSource
monkey event queue

Fields Summary
private static final int[]
NAV_KEYS
Key events that move around the UI.
private static final int[]
MAJOR_NAV_KEYS
Key events that perform major navigation options (so shouldn't be sent as much).
private static final int[]
SYS_KEYS
Key events that perform system operations.
private static final String[]
KEY_NAMES
Nice names for all key events.
public static final int
FACTOR_TOUCH
public static final int
FACTOR_MOTION
public static final int
FACTOR_TRACKBALL
public static final int
FACTOR_NAV
public static final int
FACTOR_MAJORNAV
public static final int
FACTOR_SYSOPS
public static final int
FACTOR_APPSWITCH
public static final int
FACTOR_FLIP
public static final int
FACTOR_ANYTHING
public static final int
FACTORZ_COUNT
private float[]
mFactors
percentages for each type of event. These will be remapped to working values after we read any optional values.
private ArrayList
mMainApps
private int
mEventCount
private LinkedList
mQ
private Random
mRandom
private int
mVerbose
private long
mThrottle
private boolean
mKeyboardOpen
Constructors Summary
public MonkeySourceRandom(long seed, ArrayList MainApps, long throttle)

        // default values for random distributions
        // note, these are straight percentages, to match user input (cmd line args)
        // but they will be converted to 0..1 values before the main loop runs.
        mFactors[FACTOR_TOUCH] = 15.0f;
        mFactors[FACTOR_MOTION] = 10.0f;
        mFactors[FACTOR_TRACKBALL] = 15.0f;
        mFactors[FACTOR_NAV] = 25.0f;
        mFactors[FACTOR_MAJORNAV] = 15.0f;
        mFactors[FACTOR_SYSOPS] = 2.0f;
        mFactors[FACTOR_APPSWITCH] = 2.0f;
        mFactors[FACTOR_FLIP] = 1.0f;
        mFactors[FACTOR_ANYTHING] = 15.0f;
        
        mRandom = new SecureRandom();
        mRandom.setSeed((seed == 0) ? -1 : seed);
        mMainApps = MainApps;
        mThrottle = throttle;
    
Methods Summary
private voidaddThrottle()

        mQ.addLast(new MonkeyThrottleEvent(MonkeyEvent.EVENT_TYPE_THROTTLE, mThrottle));
    
private booleanadjustEventFactors()
Adjust the percentages (after applying user values) and then normalize to a 0..1 scale.

        // go through all values and compute totals for user & default values
        float userSum = 0.0f;
        float defaultSum = 0.0f;
        int defaultCount = 0;
        for (int i = 0; i < FACTORZ_COUNT; ++i) {
            if (mFactors[i] <= 0.0f) {   // user values are zero or negative
                userSum -= mFactors[i];
            } else {
                defaultSum += mFactors[i];
                ++defaultCount;
            }            
        }
        
        // if the user request was > 100%, reject it
        if (userSum > 100.0f) {
            System.err.println("** Event weights > 100%");
            return false;
        }
        
        // if the user specified all of the weights, then they need to be 100%
        if (defaultCount == 0 && (userSum < 99.9f || userSum > 100.1f)) {
            System.err.println("** Event weights != 100%");
            return false;
        }
        
        // compute the adjustment necessary
        float defaultsTarget = (100.0f - userSum);
        float defaultsAdjustment = defaultsTarget / defaultSum;
        
        // fix all values, by adjusting defaults, or flipping user values back to >0
        for (int i = 0; i < FACTORZ_COUNT; ++i) {
            if (mFactors[i] <= 0.0f) {   // user values are zero or negative
                mFactors[i] = -mFactors[i];
            } else {
                mFactors[i] *= defaultsAdjustment;
            }
        }
        
        // if verbose, show factors
        
        if (mVerbose > 0) {
            System.out.println("// Event percentages:");
            for (int i = 0; i < FACTORZ_COUNT; ++i) {
                System.out.println("//   " + i + ": " + mFactors[i] + "%");
            }
        } 
        
        // finally, normalize and convert to running sum
        float sum = 0.0f;
        for (int i = 0; i < FACTORZ_COUNT; ++i) {
            sum += mFactors[i] / 100.0f;
            mFactors[i] = sum;
        }        
        return true;
    
public voidgenerateActivity()
generate an activity event

        MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
                mRandom.nextInt(mMainApps.size())));
        mQ.addLast(e);
    
private voidgenerateEvents()
generate a random event based on mFactor

        
        float cls = mRandom.nextFloat();
        int lastKey = 0;

        boolean touchEvent = cls < mFactors[FACTOR_TOUCH];
        boolean motionEvent = !touchEvent && (cls < mFactors[FACTOR_MOTION]);
        if (touchEvent || motionEvent) {            
            generateMotionEvent(mRandom, motionEvent);
            return;
        }
        
        if (cls < mFactors[FACTOR_TRACKBALL]) {            
            generateTrackballEvent(mRandom);
            return;
        }

        // The remaining event categories are injected as key events
        if (cls < mFactors[FACTOR_NAV]) {
            lastKey = NAV_KEYS[mRandom.nextInt(NAV_KEYS.length)];
        } else if (cls < mFactors[FACTOR_MAJORNAV]) {
            lastKey = MAJOR_NAV_KEYS[mRandom.nextInt(MAJOR_NAV_KEYS.length)];
        } else if (cls < mFactors[FACTOR_SYSOPS]) {
            lastKey = SYS_KEYS[mRandom.nextInt(SYS_KEYS.length)];
        } else if (cls < mFactors[FACTOR_APPSWITCH]) {
            MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
                    mRandom.nextInt(mMainApps.size())));
            mQ.addLast(e);
            addThrottle();
            return;
        } else if (cls < mFactors[FACTOR_FLIP]) {
            MonkeyFlipEvent e = new MonkeyFlipEvent(mKeyboardOpen);
            mKeyboardOpen = !mKeyboardOpen;
            mQ.addLast(e);
            addThrottle();
            return;
        } else {
            lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1);
        }
                
        MonkeyKeyEvent e = new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, lastKey);
        mQ.addLast(e);
        
        e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey);
        mQ.addLast(e);
        
        addThrottle();
    
private voidgenerateMotionEvent(java.util.Random random, boolean motionEvent)
Generates a random motion event. This method counts a down, move, and up as multiple events. TODO: Test & fix the selectors when non-zero percentages TODO: Longpress. TODO: Fling. TODO: Meta state TODO: More useful than the random walk here would be to pick a single random direction and distance, and divvy it up into a random number of segments. (This would serve to generate fling gestures, which are important).

param
random Random number source for positioning
param
motionEvent If false, touch/release. If true, touch/move/release.

        
        Display display = WindowManagerImpl.getDefault().getDefaultDisplay();

        float x = Math.abs(random.nextInt() % display.getWidth());
        float y = Math.abs(random.nextInt() % display.getHeight());
        long downAt = SystemClock.uptimeMillis();
        long eventTime = SystemClock.uptimeMillis();
        if (downAt == -1) {
            downAt = eventTime;
        }
        
        MonkeyMotionEvent e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, 
                downAt, MotionEvent.ACTION_DOWN, x, y, 0);        
        e.setIntermediateNote(false);        
        mQ.addLast(e);
        
        // sometimes we'll move during the touch
        if (motionEvent) {
            int count = random.nextInt(10);
            for (int i = 0; i < count; i++) {
                // generate some slop in the up event
                x = (x + (random.nextInt() % 10)) % display.getWidth();
                y = (y + (random.nextInt() % 10)) % display.getHeight();
                
                e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, 
                        downAt, MotionEvent.ACTION_MOVE, x, y, 0);        
                e.setIntermediateNote(true);        
                mQ.addLast(e);
            }
        }

        // TODO generate some slop in the up event
        e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_POINTER, 
                downAt, MotionEvent.ACTION_UP, x, y, 0);        
        e.setIntermediateNote(false);        
        mQ.addLast(e);
        addThrottle();
    
private voidgenerateTrackballEvent(java.util.Random random)
Generates a random trackball event. This consists of a sequence of small moves, followed by an optional single click. TODO: Longpress. TODO: Meta state TODO: Parameterize the % clicked TODO: More useful than the random walk here would be to pick a single random direction and distance, and divvy it up into a random number of segments. (This would serve to generate fling gestures, which are important).

param
random Random number source for positioning

        Display display = WindowManagerImpl.getDefault().getDefaultDisplay();

        boolean drop = false;
        int count = random.nextInt(10);
        MonkeyMotionEvent e;
        for (int i = 0; i < 10; ++i) {
            // generate a small random step
            int dX = random.nextInt(10) - 5;
            int dY = random.nextInt(10) - 5;
            
            
            e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, -1, 
                    MotionEvent.ACTION_MOVE, dX, dY, 0);        
            e.setIntermediateNote(i > 0);        
            mQ.addLast(e);
        }
        
        // 10% of trackball moves end with a click
        if (0 == random.nextInt(10)) {
            long downAt = SystemClock.uptimeMillis();
            
            
            e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, 
                    MotionEvent.ACTION_DOWN, 0, 0, 0);        
            e.setIntermediateNote(true);        
            mQ.addLast(e);
            
            
            e = new MonkeyMotionEvent(MonkeyEvent.EVENT_TYPE_TRACKBALL, downAt, 
                    MotionEvent.ACTION_UP, 0, 0, 0);        
            e.setIntermediateNote(false);        
            mQ.addLast(e);
        }        
        addThrottle();
    
public static java.lang.StringgetKeyName(int keycode)

        return KEY_NAMES[keycode];
    
public static java.lang.StringgetLastKeyName()

return
the last name in the key list


                  
        
        return KEY_NAMES[KeyEvent.getMaxKeyCode() + 1];
    
public MonkeyEventgetNextEvent()
if the queue is empty, we generate events first

return
the first event in the queue

        if (mQ.isEmpty()) {
                generateEvents();
        }        
        mEventCount++;        
        MonkeyEvent e = mQ.getFirst();        
        mQ.removeFirst();        
        return e;
    
public voidsetFactors(float[] factors)
set the factors

param
factors: percentages for each type of event

        int c = FACTORZ_COUNT;
        if (factors.length < c) {
            c = factors.length;
        }        
        for (int i = 0; i < c; i++)
            mFactors[i] = factors[i];
    
public voidsetFactors(int index, float v)

        mFactors[index] = v;
    
public voidsetVerbose(int verbose)

        mVerbose = verbose;
    
public booleanvalidate()

        //check factors
        return adjustEventFactors();