網(wǎng)上的文章很少煌抒,我感覺這個東西搞得好也是完全可以和adb 的觸摸媲美的命浴。
這東西主要是用在神之手實現(xiàn)不需要root的情況下自動點擊app.也不需要開啟那些無障礙服務(wù)。
目前我已經(jīng)用這個做了鍵盤自動輸入驗證碼各種頁面自動填表椅您。
要點擊子view,使用dispatchTouchEvent
如果只需要點擊當前外冀,而且能找到當前view,則直接調(diào)用此view的onTouchEvent方法。
點擊屏幕中的某個view通過父view方式
View decorView = mainActivity.getWindow().getDecorView();
int[] outlocation = new int[2];
btn_btn1.getLocationInWindow(outlocation);
int y = outlocation[1];
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下時間:");
int rawX=outlocation[0];
int rawY=outlocation[1];
rawY=rawY+10;
int finalRawY = rawY;
int width = decorView.getWidth();
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
decorView.dispatchTouchEvent(obtain);
decorView.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_MOVE, width, finalRawY, 0);
decorView.dispatchTouchEvent(obtainUp);
Log.w(TAG, "長按完成,模擬抬起事件");
}
}, 2000);
decorView.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, width, finalRawY, 0);
decorView.dispatchTouchEvent(obtainUp);
Log.w(TAG, "長按完成,模擬抬起事件");
}
}, 6000);
Log.w(TAG, "Y:" + y + ",screenHeight:" + decorView.getHeight() + "");
}
},1200);
測試觸摸效果的代碼掀泳。
package cn.qssq666.main;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.Random;
/**
* Created by qssq on 2018/4/5 qssq666@foxmail.com
*/
public class UiClickUtil {
private static final String TAG = "UiClickUtil";
public static void clickView(View paramX) {
performViewOnTouchEvent(paramX, 0);
}
public static void longPressView(View paramX) {
longPressView(paramX, 2 * 1000);
}
/**
* @param paramX
* @param actionUpTime 長按時間
*/
public static void longPressView(View paramX, int actionUpTime) {
performViewOnTouchEvent(paramX, actionUpTime);
}
public static void performViewOnTouchEvent(View paramX, int actionUpTime) {
int[] actualRawX = getActualRawX(paramX);
performViewOnTouchEvent(paramX, actualRawX[0], actualRawX[1], actionUpTime);
}
public static void performViewOnTouchEvent(View view, final int rawX, final int rawY, int actionUpTime) {
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下時間:");
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
view.onTouchEvent(obtain);
view.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, rawX, rawY, 0);
view.onTouchEvent(obtainUp);
Log.w(TAG, "長按完成,模擬抬起事件");
}
}, actionUpTime);
}
public static void performClickChildView(View view, final int rawX, final int rawY, int actionUpTime) {
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下時間:");
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
view.dispatchTouchEvent(obtain);
view.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, rawX, rawY, 0);
view.dispatchTouchEvent(obtainUp);
Log.w(TAG, "長按完成,模擬抬起事件");
}
}, actionUpTime);
}
public static int[] getActualRawX(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
location[0] = location[0] + new Random().nextInt(view.getWidth());
location[1] = location[1] + new Random().nextInt(view.getHeight());
return location;
}
public static void performUpEvent(View paramX) {
int[] actualRawX = getActualRawX(paramX);
performUpEvent(paramX, actualRawX[0], actualRawX[1]);
}
public static void performUpEvent(View paramX, int rawX, int rawY) {
MotionEvent obtain = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 5000, MotionEvent.ACTION_UP, rawX, rawY, 0);
paramX.onTouchEvent(obtain);
}
public static void performMoveEvent(View paramX) {
int[] actualRawX = getActualRawX(paramX);
performMoveEvent(paramX, actualRawX[0], actualRawX[1]);
}
public static void performMoveEvent(View paramX, int rawX, int rawY) {
MotionEvent obtain = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 5000, MotionEvent.ACTION_MOVE, rawX, rawY, 0);
paramX.onTouchEvent(obtain);
}
}
package cn.qssq666.ui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.view.View;
public class MyView extends SurfaceView implements Callback, View.OnTouchListener {
private static final String TAG = "MyView";
private Paint p = new Paint();
private Path path = new Path();
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
p.setColor(Color.RED);
p.setTextSize(10);
p.setAntiAlias(true);
p.setStyle(Paint.Style.STROKE);
setOnTouchListener(this);
}
public void draw() {
Canvas canvas = getHolder().lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, p);
getHolder().unlockCanvasAndPost(canvas);
}
public void clear() {
path.reset();
draw();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
draw();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(event.getX(), event.getY());
draw();
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(event.getX(), event.getY());
Log.w(TAG,"屏幕Y"+event.getRawY());
draw();
break;
}
return true;
}
}
getRawY
配合getLocationInWindow()
因此父view點擊子view,用這兩個進行測試才比較合理雪隧,精準。
getY是相對于view自身空間员舵,
一個某自定義繪制的abcd索引view點擊第一個條目脑沿,忽略標題高度,經(jīng)過計算標題高度17dp 所以加上17+第一個條目的高度減去一半就點了第一個條目中間
try {
int rl_content = ResourcesUtil.getId(decorView.getContext(), "rl_content");
ViewGroup currentView = (ViewGroup) decorView.findViewById(rl_content);
if (currentView == null || currentView.getChildCount() == 0) {
ToastUtils.showToast("無法完成自動選擇,請手動選擇");
Commons.finishAndclearFirstTask();
} else {
}
int[] outlocation = new int[2];
currentView.getLocationInWindow(outlocation);
int y = outlocation[1] +AppUtil.dip2px(AppContext.getInstance(), 20);//這里的30是為了找到這個容器往下面一點點擊一個item.
int x=outlocation[0];
UiClickUtil.performClickChildView(decorView, x+currentView.getWidth()/2, y, 2000);
// UiClickUtil.performClickChildView(decorView, x+currentView.getWidth()/2, 455, 2000);
// View view = viewGroup.getChildAt(0);
// view.callOnClick();
Log.w(TAG, "getRawY:" + y + ",screenHeight:" + decorView.getHeight() + "rawx:"+x+",rawY:"+outlocation[1]);
ToastUtils.showToast("已點擊完成");
} catch (Throwable e) {
Log.w(TAG, "ERROR", e);
}