-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from Jinnrry/feature-accessibility
V2.0 WEB API实现
- Loading branch information
Showing
30 changed files
with
805 additions
and
390 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
Android/app/src/main/java/cn/xjiangwei/RobotHelper/Accessibility/AbstractNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
Android/app/src/main/java/cn/xjiangwei/RobotHelper/Accessibility/HttpServer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
Android/app/src/main/java/cn/xjiangwei/RobotHelper/Accessibility/INode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
Oops, something went wrong.