Skip to content

Commit

Permalink
Merge pull request #8 from Jinnrry/feature-accessibility
Browse files Browse the repository at this point in the history
V2.0 WEB API实现
  • Loading branch information
Jinnrry authored Jul 28, 2020
2 parents 2d3e8eb + 092f905 commit 0d0a22a
Show file tree
Hide file tree
Showing 30 changed files with 805 additions and 390 deletions.
1 change: 1 addition & 0 deletions Android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ dependencies {
implementation 'com.lahm.library:easy-protector-release:1.1.0'
implementation project(path: ':tesseract4android-2.0.0')
implementation project(path: ':opencv-android341')
implementation 'com.nanohttpd:nanohttpd-webserver:2.2.0'
}

32 changes: 22 additions & 10 deletions Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.xjiangwei.RobotHelper">
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<!--android 9.0上使用前台服务,需要添加权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> <!-- android 9.0上使用前台服务,需要添加权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name="cn.xjiangwei.RobotHelper.MainApplication"
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<service
android:name=".Service.Accessibility"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
<service
android:name="cn.xjiangwei.RobotHelper.Service.RunTime"
android:name=".Service.RunTime"
android:enabled="true"
android:exported="false"></service>
<!-- 是否是xposed模块,xposed根据这个来判断是否是模块 -->
android:exported="false" /> <!-- 是否是xposed模块,xposed根据这个来判断是否是模块 -->
<meta-data
android:name="xposedmodule"
android:value="true" /> <!-- 模块描述,显示在xposed模块列表那里第二行 -->
Expand All @@ -33,7 +44,8 @@
<meta-data
android:name="xposedminversion"
android:value="30" />
<activity android:name="cn.xjiangwei.RobotHelper.MainActivity">

<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cn.xjiangwei.RobotHelper.Accessibility;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import cn.xjiangwei.RobotHelper.Accessibility.exceptions.UnableToSetAttributeException;

/**
* Created by adolli on 2017/7/19.
*/

public abstract class AbstractNode implements INode {
// tree node interface
public AbstractNode getParent() {
return null;
}

public abstract Iterable<AbstractNode> getChildren();

// node interface
public void setAttr(String attrName, Object attrVal) {
throw new UnableToSetAttributeException(String.format("%s=%s", attrName, attrVal), null, "Method not implemented.");
}

public Object getAttr(String attrName) {
Map<String, Object> defaultAttrs = new HashMap<>();
defaultAttrs.put("name", "<Root>");
defaultAttrs.put("type", "Root");
defaultAttrs.put("visible", true);
defaultAttrs.put("pos", new float[] {0, 0});
defaultAttrs.put("size", new float[] {0, 0});
defaultAttrs.put("scale", new float[] {0, 0});
defaultAttrs.put("anchorPoint", new float[] {0.5f, 0.5f});
Map<String, Object> zOrders = new HashMap<>();
zOrders.put("global", 0);
zOrders.put("local", 0);
defaultAttrs.put("zOrders", zOrders);

if (defaultAttrs.containsKey(attrName)) {
return defaultAttrs.get(attrName);
} else {
return null;
}
}

public List<String> getAvailableAttributeNames() {
List<String> ret = new LinkedList<>();
String[] a = new String[] {
"name",
"type",
"visible",
"pos",
"size",
"scale",
"anchorPoint",
"zOrders",
};
for (String n : a) {
ret.add(n);
}
return ret;
}

// method for dumper only
public Map<String, Object> enumerateAttrs() {
Map<String, Object> ret = new HashMap<>();
for (String attrName : getAvailableAttributeNames()) {
ret.put(attrName, getAttr(attrName));
}
return ret;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package cn.xjiangwei.RobotHelper.Accessibility;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.view.accessibility.AccessibilityNodeInfo;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import cn.xjiangwei.RobotHelper.MainApplication;
import cn.xjiangwei.RobotHelper.Service.Accessibility;
import cn.xjiangwei.RobotHelper.Tools.Robot;
import fi.iki.elonen.NanoHTTPD;

import static android.support.v4.content.ContextCompat.getSystemService;

public class HttpServer extends NanoHTTPD {


public boolean runing;

public HttpServer() {
super("0.0.0.0", 1082);
try {
start(5000, true);
runing = true;
} catch (IOException e) {
e.printStackTrace();
}
}

public void stop() {
super.stop();
runing = false;
}


public void start() {
try {
start(5000, true);
} catch (IOException e) {
e.printStackTrace();
}
runing = true;
}

@Override
public Response serve(IHTTPSession session) {
String path = session.getUri();
Map<String, String> parms = session.getParms();
String ret = "[]";
String mimeType = "application/json; charset=utf-8";
switch (path) {
case "/dom":
if (Accessibility.DOM == null) {
ret = "{\"tip\":\"无障碍服务未开启!\"}";
} else if (parms.containsKey("id")) {
ret = dumpHierarchyImpl(Accessibility.DOM.findAccessibilityNodeInfosByViewId(parms.get("id")), false).toString();
} else {
ret = dumpHierarchyImpl(new Node(Accessibility.DOM, 1440, 3120), false).toString();
}
break;
case "/sceenSize":
ret = "{\"w\": " + MainApplication.sceenWidth + " , \"h\":" + MainApplication.sceenHeight + " }";
break;
case "/swipe":
try {
Robot.swipe(Float.parseFloat(parms.get("start_x")), Float.parseFloat(parms.get("start_y")), Float.parseFloat(parms.get("end_x")), Float.parseFloat(parms.get("end_y")), Float.parseFloat(parms.get("duration")));
ret = "{\"code\":200,\"msg\":\"success\"}";
} catch (Exception e) {
ret = "{\"code\":500,\"msg\":\"检查是否开启xposed\"}";
}
break;
case "/tap":
try {
Robot.tap(Integer.parseInt(parms.get("x")), Integer.parseInt(parms.get("y")), (long) (Float.parseFloat(parms.get("delay")) * 1000));
ret = "{\"code\":200,\"msg\":\"success\"}";
} catch (Exception e) {
ret = "{\"code\":500,\"msg\":\"检查是否开启xposed\"}";
}
break;
case "/input":
try {
Robot.input(parms.get("input"));
ret = "{\"code\":200,\"msg\":\"success\"}";
} catch (Exception e) {
System.out.println(e.toString());
ret = "{\"code\":500,\"msg\":\"检查是否开启xposed\"}";
}
break;
case "/clipboard":
ClipboardManager cm = (ClipboardManager) MainApplication.getInstance().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData mClipData = ClipData.newPlainText("RobotHelp", parms.get("str"));
cm.setPrimaryClip(mClipData);
ret = "{\"code\":200,\"msg\":\"success\"}";
break;
}


return newFixedLengthResponse(Response.Status.OK, mimeType, ret);
}


public JSONArray dumpHierarchyImpl(List<AccessibilityNodeInfo> nodes, boolean onlyVisibleNode) {
JSONArray jsonArray = new JSONArray();
for (AccessibilityNodeInfo node : nodes) {
jsonArray.put(dumpHierarchyImpl(new Node(node, 3120, 1440), onlyVisibleNode));
}

return jsonArray;
}


public JSONObject dumpHierarchyImpl(AbstractNode node, boolean onlyVisibleNode) {
if (node == null) {
// return if still null
return null;
}

JSONObject payload = new JSONObject();
for (Map.Entry<String, Object> attr : node.enumerateAttrs().entrySet()) {
try {
payload.put(attr.getKey(), attr.getValue());
} catch (JSONException e) {
e.printStackTrace();
}
}

JSONObject result = new JSONObject();
JSONArray children = new JSONArray();

for (AbstractNode child : node.getChildren()) {
if (!onlyVisibleNode || (boolean) child.getAttr("visible")) {
children.put(this.dumpHierarchyImpl(child, onlyVisibleNode));
}
}
if (children.length() > 0) {
try {
result.put("children", children);
} catch (JSONException e) {
e.printStackTrace();
}
}

try {
result.put("name", node.getAttr("name"));
result.put("payload", payload);
} catch (JSONException e) {
e.printStackTrace();
}

return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cn.xjiangwei.RobotHelper.Accessibility;


import cn.xjiangwei.RobotHelper.Accessibility.exceptions.NodeHasBeenRemovedException;
import cn.xjiangwei.RobotHelper.Accessibility.exceptions.UnableToSetAttributeException;

/**
* Created by adolli on 2017/7/19.
*/

public interface INode {
Object getAttr(String attrName) throws NodeHasBeenRemovedException;
void setAttr(String attrName, Object value) throws UnableToSetAttributeException, NodeHasBeenRemovedException;
}
Loading

0 comments on commit 0d0a22a

Please sign in to comment.