TellMeNotice/app/src/main/java/com/itrycn/ta/AccessibilityOperator.java
如果当时 732d4c7c64 2020-12-18 V1.0.1
*.[新增]支持通过wifi名称来判断是否在上班。
*.[新增]增加游戏模式(尚未完成)。
*.[改进]不连公司wifi的情况下,个性化购物和淘口令声音。
2020-12-18 23:18:00 +08:00

602 lines
20 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.itrycn.ta;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Path;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.provider.DocumentsContract;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import com.itrycn.ta.script.ScriptSystemInfo;
import com.itrycn.ta.utils.AccessibilityLog;
import java.io.File;
import java.io.IOException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* Created by popfisher on 2017/7/11.
*/
@TargetApi(16)
public class AccessibilityOperator {
private Context mContext;
private static AccessibilityOperator mInstance = new AccessibilityOperator();
private AccessibilityEvent mAccessibilityEvent;
private AccessibilityService mAccessibilityService;
public Handler UIHandler;
public boolean IsExit=false;
private boolean result_bool=false;
public ScriptSystemInfo SystemInfo=ScriptSystemInfo.getInstance();
private AccessibilityOperator() {
}
public static AccessibilityOperator getInstance() {
return mInstance;
}
public void init(Context context) {
mContext = context;
ScriptSystemInfo.getInstance().init(context);
}
public void updateEvent(AccessibilityService service, AccessibilityEvent event) {
if (service != null && mAccessibilityService == null) {
mAccessibilityService = service;
}
if (event != null) {
mAccessibilityEvent = event;
}
}
public boolean isServiceRunning() {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(Short.MAX_VALUE);
for (ActivityManager.RunningServiceInfo info : services) {
if (info.service.getClassName().equals("com.itryn.ta.AccessibilityTaService")) {
return true;
}
}
return false;
}
private AccessibilityNodeInfo getRootNodeInfo() {
AccessibilityEvent curEvent = mAccessibilityEvent;
AccessibilityNodeInfo nodeInfo = null;
if (Build.VERSION.SDK_INT >= 16) {
// 建议使用getRootInActiveWindow这样不依赖当前的事件类型
if (mAccessibilityService != null) {
nodeInfo = mAccessibilityService.getRootInActiveWindow();
if(nodeInfo==null)
{
Toast("无法获取当前界面内容1");
}
//AccessibilityLog.printLog("nodeInfo: " + nodeInfo);
}
else{
Toast("辅助服务开启失败,请重启软件");
}
// 下面这个必须依赖当前的AccessibilityEvent
// nodeInfo = curEvent.getSource();
} else {
nodeInfo = curEvent.getSource();
if(nodeInfo==null)
{
Toast("无法获取当前界面内容2");
}
}
return nodeInfo;
}
/**
* 根据Text搜索所有符合条件的节点, 精确搜索方式
*/
public List<AccessibilityNodeInfo> findNodesByText(String text) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return FindByText(nodeInfo,text);
}
return null;
}
/**
* 根据Text搜索所有符合条件的节点, 精确搜索方式
*/
public List<AccessibilityNodeInfo> findNodesByText(String[] text) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return FindByText(nodeInfo,text);
}
return null;
}
/**
* 根据Text搜索所有符合条件的节点, 模糊搜索方式
*/
public List<AccessibilityNodeInfo> findNodesByContainsText(String text) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return FindByContainsText(nodeInfo,text);
}
return null;
}
/**
* 根据Text搜索所有符合条件的节点, 模糊搜索方式
*/
public List<AccessibilityNodeInfo> findNodesByContainsText(String[] text) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return FindByContainsText(nodeInfo,text);
}
return null;
}
/**
* 根据Text搜索所有符合条件的节点, 精确搜索方式
*/
public List<AccessibilityNodeInfo> FindByText(AccessibilityNodeInfo info,String text) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0 && info.getText()!=null) {
if(info.getText().toString().equals(text))
{
list.add(info);
}
} else {
for (int i = 0; i < info.getChildCount(); i++) {
if(info.getChild(i)!=null){
list.addAll(FindByText(info.getChild(i),text));
}
}
}
return list;
}
/**
* 根据Text搜索所有符合条件的节点, 精确搜索方式
*/
public List<AccessibilityNodeInfo> FindByText(AccessibilityNodeInfo info,String[] text) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0 && info.getText()!=null) {
for (int k=0;k<text.length;k++)
{
if(info.getText().toString().equals(text[k]))
{
list.add(info);
break;
}
}
} else {
for (int i = 0; i < info.getChildCount(); i++) {
if(info.getChild(i)!=null){
list.addAll(FindByText(info.getChild(i),text));
}
}
}
return list;
}
/**
* 根据Text搜索所有符合条件的节点, 模糊搜索方式
*/
public List<AccessibilityNodeInfo> FindByContainsText(AccessibilityNodeInfo info,String[] text) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0 && info.getText()!=null) {
for (int k=0;k<text.length;k++)
{
if(info.getText().toString().contains(text[k]))
{
list.add(info);
break;
}
}
} else {
for (int i = 0; i < info.getChildCount(); i++) {
if(info.getChild(i)!=null){
list.addAll(FindByContainsText(info.getChild(i),text));
}
}
}
return list;
}
/**
* 根据Text搜索所有符合条件的节点, 模糊搜索方式
*/
public List<AccessibilityNodeInfo> FindByContainsText(AccessibilityNodeInfo info,String text) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0 && info.getText()!=null) {
if(info.getText().toString().contains(text))
{
list.add(info);
}
} else {
for (int i = 0; i < info.getChildCount(); i++) {
if(info.getChild(i)!=null){
list.addAll(FindByContainsText(info.getChild(i),text));
}
}
}
return list;
}
/**
* 获取当前页面上的所有控件信息
*/
public List<AccessibilityNodeInfo> GetAllNodes() {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return GetAllNodes(nodeInfo);
}
return null;
}
/**
* 获取当前页面上的所有控件信息
*/
public List<AccessibilityNodeInfo> GetAllNodes(AccessibilityNodeInfo info) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0) {
list.add(info);
} else {
for (int i = 0; i < info.getChildCount(); i++) {
list.add(info);
if(info.getChild(i)!=null){
list.addAll(GetAllNodes(info.getChild(i)));
}
}
}
return list;
}
/**
* 获取当前页面上的所有没有子控件的控件信息
*/
public List<AccessibilityNodeInfo> GetAllNoChildsNodes() {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return GetAllNoChildsNodes(nodeInfo);
}
return null;
}
/**
* 获取当前页面上的所有没有子控件的控件信息
*/
public List<AccessibilityNodeInfo> GetAllNoChildsNodes(AccessibilityNodeInfo info) {
List<AccessibilityNodeInfo> list=new ArrayList<AccessibilityNodeInfo>();
if (info.getChildCount() == 0) {
list.add(info);
} else {
for (int i = 0; i < info.getChildCount(); i++) {
if(info.getChild(i)!=null){
list.addAll(GetAllNodes(info.getChild(i)));
}
}
}
return list;
}
/**
* 根据View的ID搜索符合条件的节点,精确搜索方式;
* 这个只适用于自己写的界面因为ID可能重复
* api要求18及以上
* @param viewId
*/
public List<AccessibilityNodeInfo> findNodesById(String viewId) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
if (Build.VERSION.SDK_INT >= 18) {
return nodeInfo.findAccessibilityNodeInfosByViewId(viewId);
}
}
return null;
}
/**
* 按文本来点击
* @param text
* @return 是否点击成功
*/
public boolean clickByText(String text) {
return performClick(findNodesByText(text));
}
/**
* 按文本来点击
* @param text
* @return 是否点击成功
*/
public boolean clickByText(String[] text) {
return performClick(findNodesByText(text));
}
/**
* 按文本来点击,忽略黑名单中的控件
* @param text
* @return 是否点击成功
*/
public boolean clickByText(String[] text,Rect[] blackrect) {
runOnUiThread(new Runnable(){
public void run(){
List<AccessibilityNodeInfo> list=findNodesByText(text);
if(list==null)
{
//Toast("界面查找出错...");
result_bool=false;
}
else {
for (int i = list.size() - 1; i >= 0; i--) {
AccessibilityNodeInfo node = list.get(i);
Rect rect = new Rect();
node.getBoundsInScreen(rect);
for (int r = 0; r < blackrect.length; r++) {
if (isIntersect(rect, blackrect[r])) {
list.remove(i);
}
}
}
result_bool = performClick(list);
}
}
});
return result_bool;
}
private boolean isIntersect(Rect a, Rect b) {
return a.left <= b.right && b.left <= a.right && a.top <= b.bottom
&& b.top <= a.bottom;
}
/**
* 根据View的ID搜索符合条件的节点,精确搜索方式;
* 这个只适用于自己写的界面因为ID可能重复
* api要求18及以上
* @param viewId
* @return 是否点击成功
*/
public boolean clickById(String viewId) {
return performClick(findNodesById(viewId));
}
public boolean performClick(List<AccessibilityNodeInfo> nodeInfos) {
if (nodeInfos != null && !nodeInfos.isEmpty()) {
AccessibilityNodeInfo node;
for (int i = 0; i < nodeInfos.size(); i++) {
node = nodeInfos.get(i);
// 获得点击View的类型
AccessibilityLog.printLog("View类型" + node.getClassName());
// 进行模拟点击
if (node.isEnabled()) {
return ClickByNode(node);
}
}
}
return false;
}
/**
* 从指定坐标1滑动到指定坐标2
* @return 是否点击成功
*/
public boolean Gesture(int x1,int y1,int x2,int y2,long duration){//仿滑动
if(IsExit){return false;}
if(mAccessibilityService==null){Toast("辅助服务已失效"); return false;}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
runOnUiThread(new Runnable(){
public void run(){
Path path = new Path();
path.moveTo(x1, y1);//滑动起点
path.lineTo(x2, y2);//滑动终点
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription description = builder.addStroke(new GestureDescription.StrokeDescription(path, 0, duration)).build();
//100L 第一个是开始的时间,第二个是持续时间
result_bool= mAccessibilityService.dispatchGesture(description, new MyCallBack(), null);
}
});
return result_bool;
}
return false;
}
/**
* 从指定坐标1滑动到指定坐标2
* @return 是否点击成功
*/
public boolean Gesture(Path path,long startTime,long duration){//仿滑动
if(IsExit){return false;}
if(mAccessibilityService==null){return false;}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription description = builder.addStroke(new GestureDescription.StrokeDescription(path, startTime, duration)).build();
//100L 第一个是开始的时间,第二个是持续时间
return mAccessibilityService.dispatchGesture(description, new MyCallBack(), null);
}
return false;
}
/**
* 获取控件矩形参数
* @return 返回矩形
*/
public Rect GetBounds(AccessibilityNodeInfo node){
Rect rect = new Rect();
if(node!=null)
{
node.getBoundsInScreen(rect);
}
return rect;
}
/**
* 点击指定控件
* @return 是否点击成功
*/
public boolean ClickByNode(AccessibilityNodeInfo node){//点击
if(node!=null)
{
Rect rect = new Rect();
node.getBoundsInScreen(rect);
int x=(rect.left+rect.right)/2;
int y = (rect.top + rect.bottom) / 2;
//设置随机位移,防止作弊被发现
int width_d=RandomInt(0,((int)rect.width()/2)-2);
int height_d=RandomInt(0,((int)rect.height()/2)-2);
int add=RandomInt(0,1);
if(add==0)
{
x=x-width_d;
y=y-height_d;
}
else{
x=x+width_d;
y=y+height_d;
}
return Click(x,y);
}
return false;
}
/**
* 生成随机数
* @return
*/
public int RandomInt(int min,int max)
{
return (new Random()).nextInt((max - min) + 1) + min;
}
/**
* 生成随机数
* @return
*/
public long RandomLong(long min,long max)
{
Random random = new Random();
return ( long )random.nextDouble()*(max-min) + min;
}
/**
* 点击指定坐标
* @return 是否点击成功
*/
public boolean Click(int x,int y){//点击
return Press(x,y,150);
}
/**
* 长点击指定坐标
* @return 是否点击成功
*/
public boolean LongClick(int x,int y){//点击
return Press(x,y,700);
}
/**
* 点击指定坐标
* @return 是否点击成功
*/
public boolean Press(int x,int y,long delay){//点击
return Gesture(x,y,x,y,delay);
}
/**
* 运行app
* @return 是否成功
*/
public boolean LaunchApp(String packageName)
{
if(IsExit){return false;}
Intent intent =mContext.getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
return true;
}
return false;
}
/**
* 安装应用
* @param Path
*/
private void _InstallApk(String Path) {
Uri uri;
File apkFile;
try {
apkFile = new File(Path);
if(!apkFile.exists()){return;}
Intent intentInstall = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
Uri contentUri = FileProvider.getUriForFile(mContext, "com.rfid.application.MyApplication.provider", apkFile);
intentInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intentInstall.setDataAndType(contentUri, "application/vnd.android.package-archive");
}else{
intentInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentInstall.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
mContext.startActivity(intentInstall);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 休眠多少毫秒
*/
public void Sleep(long millis) {
Date date=new Date();
long addtime= date.getTime()+millis;
while(addtime>=(new Date()).getTime() && !IsExit) {
try {
Thread.sleep(10);
}
catch (Exception e){e.printStackTrace();}
}
}
/**
* 休眠多少毫秒
*/
public void Sleep(long millis_min,long millis_max) {
long R_millis=RandomLong(millis_min,millis_max);
Sleep(R_millis);
}
/**
*Toast提示
*/
public void Toast(String text)
{
runOnUiThread(new Runnable(){
public void run(){
Toast.makeText(mContext.getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
});
}
public final void runOnUiThread(Runnable action) {
if(UIHandler==null) {
action.run();
}else
{
UIHandler.post(action);
}
}
/**
*点击返回键
*/
public boolean clickBackKey() {
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
}
private boolean performGlobalAction(int action) {
if(IsExit){return false;}
if(mAccessibilityService==null){return false;}
runOnUiThread(new Runnable(){
public void run(){
result_bool= mAccessibilityService.performGlobalAction(action);
}
});
return result_bool;
}
}