个人博客:

http://www.milovetingting.cn

前言

压力测试中,一般会用到自动化测试。准备写一个APP,可以记录屏幕上的点击事件,然后通过shell命令来模拟自动执行。shell指令,比较容易实现。那么,关键的一步是获取点击的坐标。对于Android来说,为便于开发者调试,Android系统中的"开发者选项"中,有一个"指针位置"的选项。打开这个选项,点击屏幕,就会显示当前点击的位置坐标。接下来,来看一下打开选项的过程。

开发者选项页面

"开发者选项"的源码位于packages/apps/settings/src/com/android/settings/DevelopmentSettings.java文件中。

private SwitchPreference mPointerLocation;

在onCreate()方法中初始化:

mPointerLocation = findAndInitSwitchPref(POINTER_LOCATION_KEY);

findAndInitSwitchPref()方法:

private SwitchPreference findAndInitSwitchPref(String key) {
SwitchPreference pref = (SwitchPreference) findPreference(key);
if (pref == null) {
throw new IllegalArgumentException("Cannot find preference with key = " + key);
}
mAllPrefs.add(pref);
mResetSwitchPrefs.add(pref);
return pref;
}

当点击选项开关切换后,会把当前的开关状态存入Settings数据库。

private void writePointerLocationOptions() {
Settings.System.putInt(getActivity().getContentResolver(),
Settings.System.POINTER_LOCATION, mPointerLocation.isChecked() ? 1 : 0);
}

PhoneWindowManager

PhoneWindowManager的源码位于framework/base/services/core/java/com/android/server/policy/PhoneWindowManager.java文件中。

PhoneWindowManager会监听Settings.System.POINTER_LOCATION字段的变化。

class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
} void observe() {
// Observe all users' changes
ContentResolver resolver = mContext.getContentResolver();
...
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.POINTER_LOCATION), false, this,
UserHandle.USER_ALL);
...
updateSettings();
} @Override public void onChange(boolean selfChange) {
updateSettings();
updateRotation(false);
}
}

当这个值发生变化时,在updateSettings()方法中调用:

public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
synchronized (mLock) {
... if (mSystemReady) {
int pointerLocation = Settings.System.getIntForUser(resolver,
Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
if (mPointerLocationMode != pointerLocation) {
mPointerLocationMode = pointerLocation;
mHandler.sendEmptyMessage(pointerLocation != 0 ?
MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
}
}
...
}
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
PolicyControl.reloadFromSetting(mContext);
}
if (updateRotation) {
updateRotation(true);
}
}

在这个方法中,会通过Handler能送一个Message去处理。

private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ENABLE_POINTER_LOCATION:
enablePointerLocation();
break;
case MSG_DISABLE_POINTER_LOCATION:
disablePointerLocation();
break;
...
}
}
}

如果打开了"指针位置"的选项开关,那么会调用enablePointerLocation()方法

private void enablePointerLocation() {
if (mPointerLocationView == null) {
mPointerLocationView = new PointerLocationView(mContext);
mPointerLocationView.setPrintCoords(false);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
if (ActivityManager.isHighEndGfx()) {
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
lp.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
}
lp.format = PixelFormat.TRANSLUCENT;
lp.setTitle("PointerLocation");
WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(mPointerLocationView, lp);
mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
}
}

在这个方法中,首先初始化一个PointerLocationView对象,然后设置WindowManager.LayoutParams,然后将PointerLocationView实例添加到window中。再通过WindowManagerFuncs注册监听。

当屏幕上有点击时,会回调PointerLocationView的onPointerEvent()方法:

@Override
public void onPointerEvent(MotionEvent event) {
...
}

通过反射可以获取到PointerLocationView的实例,但是无法获取到WindowManagerFuncs实例。WindowManagerFuncs是在PhoneWindowManager的init()方法中初始化的。

@Override
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
...

对于WindowManager的流程不了解。这种方法看来是行不通了。。。

在网上查了相关的资料,还有种方法是通过adb的getevent命令来获取/dev/input/路径下的event事件数据,然后解析相关数据。不过对于这块也不熟悉,就没有再深入研究。

总的来说,开发基于Android的模拟点击的应用是以失败告终。后面有时间再研究下是否有其它方法可以实现。

基于Android的模拟点击探索的更多相关文章

  1. 【android】模拟点击某个指定坐标作用在View上

    /** * 模拟点击某个指定坐标作用在View上 * @param view * @param x * @param y */ public void clickView(View view,floa ...

  2. Android开发——使用ADB Shell命令实现模拟点击(支付宝自动转账实现)

    首先声明,本人反对一切利用技术的违法行为 本文的实现代码已经销毁,本文以介绍流程为主 1.这里所说的模拟点击不是在自己的APP里点击,点自己APP上的控件没什么好说的 不仅是支付宝转账,其他的获取别人 ...

  3. Android开发——Accessibility机制实现模拟点击(微信自动抢红包实现)

    1. 何为Accessibility机制 许多Android使用者因为各种情况导致他们要以不同的方式与手机交互.对于那些由于视力.听力或其它身体原因导致不能方便使用Android智能手机的用户,And ...

  4. 在Android中访问内置SE和基于SE的卡模拟(一)

    2013-10-10 编写 前言 在“十问Android NFC手机上的卡模拟”文中仅仅简单的介绍了一下相关的概念,如果需要了解基于SE的卡模拟的更多细节,也就是,究竟在Android的NFC手机上, ...

  5. Android后台监控指定app的输入内容,抢红包,模拟点击原理

    Android开启辅助功能之后可以用AccessibilityService 去后台监控指定的app的输入内容,也可以监控到app的动作 以及通知栏的动作, 抢红包其实就根据通知栏出现了红包的通知消息 ...

  6. python模拟android屏幕高频点击工具

    一.环境 windows 10  + python3.6 二.需求 1.模拟android设备高频点击事件: 2.模拟规定次数的点击事件或模拟规定时间内的点击事件: 三.code 1.模拟规定时间内的 ...

  7. Android代码模拟物理、屏幕点击事件

    一.应用中模拟物理和屏幕点击事件 例如,模拟对某个view的点击事件 private void simulateClick(View view, float x, float y) { long do ...

  8. Mac 上使用 Shell 脚本 + adb shell 实现简单的 Android 模拟点击自动化测试

    需求 在 A 界面,点击跳转到 B 界面(该界面会执行一些业务),再点击返回键出现 Dialog 弹窗,点击确认退出按钮,返回 A 界面.不断循环. 思路 一开始想到的就是按键精灵,下了 mac 版使 ...

  9. Android(Linux)模拟按键、触摸屏等事件

    前提: 在我们应用程序或者在写Android自己主动化測试时候经常会须要模拟实体按键,来给我们做測试用.这也是我要整理的目的. 基本的涉及的是Linux Input Event事件. 下面的样例基于A ...

随机推荐

  1. Javaoop 遇到的问题

    一.java 异常的捕获与处理 (免责声明:本博客里所引用的他人博客链接,只用作我个人的学习,同时非常感谢这些作者!) 1.  https://blog.csdn.net/wei_zhi/articl ...

  2. Elasticsearch【快速入门】

    前言:毕设项目还要求加了这个做大数据搜索,正好自己也比较感兴趣,就一起来学习学习吧! Elasticsearch 简介 Elasticsearch 是一个分布式.RESTful 风格的搜索和数据分析引 ...

  3. @Controller和@RestController源码解析

    2018年不知不觉已经走到了尾声,你还在为分不清@Controller和@Restcontroller而烦恼吗?这篇博文从源码层面分析这两个注解,值得一读. 首先贴一张源码的图,对比一下,左边是@Co ...

  4. .Net 反射学习

    Why?为什么使用反射 MVC ORM EF 都是用的反射.反射可以让程序的扩展性,灵活性得到加强.一起即可动态创建   what 反射原理    动态加载类库 ,先添加引用类库,或者复制debug里 ...

  5. Vue.js 学习笔记 第1章 初识Vue.js

    本篇目录: 1.1 Vue.js 是什么 1.2 如何使用Vue.js 本章主要介绍与Vue.js有关的一些概念与技术,并帮助你了解它们背后相关的工作原理. 通过对本章的学习,即使从未接触过Vue.j ...

  6. 批量数据复制SqlBulkCopy使用经验点滴(特别是超时处理)

    如果要批量复制大量的数据,用ado.net或者其他orm框架逐条读取并写入,有时会耗时太长,满足不了要求,此时SqlBulkCopy就可以出来大显身手了,相信许多人了解或使用过它. 但实际使用时,还是 ...

  7. 10分钟搭建服务器集群——Windows7系统中nginx与IIS服务器搭建集群实现负载均衡

    分布式,集群,云计算机.大数据.负载均衡.高并发······当耳边响起这些词时,做为一个菜鸟程序猿无疑心中会激动一番(或许这是判断是否是一个标准阿猿的标准吧)! 首先自己从宏观把控一下,通过上网科普自 ...

  8. python 基础语法梳理(二)

    1.gevent使用 # -*- coding: utf-8 -*- import gevent import platform from gevent import subprocess def _ ...

  9. Linux 桌面玩家指南:10. 没有 GUI 的时候应该怎么玩

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  10. 重新发现MATLAB

    现场编辑 创建不仅捕获代码的脚本 - 它们讲述了可以与他人共享的故事.自动化的上下文提示可让您在编程时快速移动,并将结果和可视化与代码一起显示. 学到更多 访问MATLAB实时脚本库         ...