/* TMTS - Android automation testing Framework.
Copyright (C) 2010-2011 TaoBao UI AutoMan Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., HuaXing road, Hangzhou,China.
Email:taichan@taobao.com,shidun@taobao.com,bingyang@taobao.com
*/
package com.taobao.tmts.framework.utils;
import java.util.ArrayList;
import java.util.regex.Pattern;
import junit.framework.Assert;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.TextView;
/**
* Some methods come from Solo Clicker.java.
*
* @author bingyang.djj, original authors is Renas Reda, renas.reda@jayway.com.
*
*/
public class ClickUtils {
private static final String LOG_TAG = "ClickUtils";
private Instrumentation inst;
private ViewUtils viewUtils;
private ActivityUtils activityUtils;
private static Sleeper sleeper;
private MatchCounter matchCounter;
private ScrollUtils scrollUtils;
public ClickUtils(Instrumentation inst, Activity activity) {
this.inst = inst;
this.sleeper = new Sleeper();
this.matchCounter = new MatchCounter();
this.activityUtils = new ActivityUtils(inst, activity, sleeper);
this.viewUtils = new ViewUtils(inst, activityUtils, sleeper);
this.scrollUtils = new ScrollUtils(inst, activityUtils, viewUtils, sleeper);
}
/**
* Click on a given view
* @throws InterruptedException
*/
public static void clickOnScreen(Instrumentation instrumentation, View view, boolean longClick) throws InterruptedException {
// if(view == null)
// Assert.assertTrue("View is null and can therefore not be clicked!", false);
int[] xy = new int[2];
view.getLocationOnScreen(xy);
final int viewWidth = view.getWidth();
final int viewHeight = view.getHeight();
final float x = xy[0] + (viewWidth / 2.0f);
float y = xy[1] + (viewHeight / 2.0f);
Log.i(LOG_TAG, "click on x: " + x + " y: "+ y);
if (longClick) {
clickLongOnScreen(instrumentation, x, y);
} else {
clickOnScreen(instrumentation, x, y);
}
}
/**
* Clicks on a given coordinate on the screen
*
* @param x the x coordinate
* @param y the y coordinate
*
*/
public static void clickOnScreen(Instrumentation instrumentation, float x, float y) {
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(downTime, eventTime,
MotionEvent.ACTION_DOWN, x, y, 0);
MotionEvent event2 = MotionEvent.obtain(downTime, eventTime,
MotionEvent.ACTION_UP, x, y, 0);
try{
instrumentation.sendPointerSync(event);
instrumentation.sendPointerSync(event2);
Log.i(LOG_TAG, "sent motionevent to click, x is " + x + " y is " + y);
}catch(SecurityException e){
Assert.assertTrue("Click can not be completed!", false);
}
}
/**
* Long clicks a given coordinate on the screen
*
* @param x the x coordinate
* @param y the y coordinate
* @throws InterruptedException
*
*/
public static void clickLongOnScreen(Instrumentation instrumentation, float x, float y) throws InterruptedException {
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
try{
instrumentation.sendPointerSync(event);
}catch(SecurityException e){
Assert.assertTrue("Click can not be completed! Something is in the way e.g. the keyboard.", false);
}
instrumentation.waitForIdleSync();
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
x + ViewConfiguration.getTouchSlop() / 2,
y + ViewConfiguration.getTouchSlop() / 2, 0);
instrumentation.sendPointerSync(event);
instrumentation.waitForIdleSync();
// if(time > 0)
// sleeper.sleep(time);
// else
Thread.sleep((int)(ViewConfiguration.getLongPressTimeout() * 1.5f));
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
instrumentation.sendPointerSync(event);
instrumentation.waitForIdleSync();
// sleeper.sleep();
}
/**
* Clicks on a specific {@link TextView} displaying a given text.
*
* @param regex the text that should be clicked on. The parameter <strong>will</strong> be interpreted as a regular expression.
* @param longClick {@code true} if the click should be a long click
* @param match the regex match that should be clicked on
* @param scroll whether to scroll to find the regex
* @param time the amount of time to long click
* @throws InterruptedException
*/
public void clickOnText(String regex, boolean longClick, int match, boolean scroll, int time) throws InterruptedException {
final Pattern pattern = Pattern.compile(regex);
// waiter.waitForText(regex, 0, TIMEOUT, scroll, true);
TextView textToClick = null;
ArrayList <TextView> textViewList = viewUtils.getCurrentViews(TextView.class);
textViewList = ViewUtils.removeInvisibleViews(textViewList);
if (match == 0) {
match = 1;
}
for (TextView textView : textViewList){
if(pattern.matcher(textView.getText().toString()).find()){
matchCounter.addMatchToCount();
}
if (matchCounter.getTotalCount() == match) {
matchCounter.resetCount();
textToClick = textView;
break;
}
}
if (textToClick != null) {
clickOnScreen(this.inst, textToClick, longClick);
} else if (scroll && scrollUtils.scroll(ScrollUtils.DOWN)) {
clickOnText(regex, longClick, match, scroll, time);
} else {
if (matchCounter.getTotalCount() > 0)
Assert.assertTrue("There are only " + matchCounter.getTotalCount() + " matches of " + regex, false);
else {
for (TextView textView : textViewList) {
Log.d(LOG_TAG, regex + " not found. Have found: " + textView.getText());
}
Assert.assertTrue("The text: " + regex + " is not found!", false);
}
matchCounter.resetCount();
}
}
}