(client) Return Tree instead of Path

Summary:
- Add return parameter to `createTouch` method: stack of node. This reference will be used to retrieve the final tree structure to be sent back to desktop app.
- `Touch` now keeps every step in component tree (I have concerned for app performance here)
- Edit test to reflect changes

Note:
- `path` will also be returned to keep backward compatibility with older server (desktop) side

Reviewed By: adityasharat

Differential Revision: D21040429

fbshipit-source-id: 6c2b9792378bf08b19fbbda1d2381df8c357170c
This commit is contained in:
Chaiwat Ekkaewnumchai
2020-05-07 03:37:49 -07:00
committed by Facebook GitHub Bot
parent f275ee00c5
commit d593409ec4
2 changed files with 109 additions and 44 deletions

View File

@@ -9,6 +9,7 @@ package com.facebook.flipper.plugins.inspector;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.util.Pair;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -25,7 +26,9 @@ import com.facebook.flipper.plugins.common.MainThreadFlipperReceiver;
import com.facebook.flipper.plugins.inspector.descriptors.ApplicationDescriptor; import com.facebook.flipper.plugins.inspector.descriptors.ApplicationDescriptor;
import com.facebook.flipper.plugins.inspector.descriptors.utils.AccessibilityUtil; import com.facebook.flipper.plugins.inspector.descriptors.utils.AccessibilityUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Stack;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class InspectorFlipperPlugin implements FlipperPlugin { public class InspectorFlipperPlugin implements FlipperPlugin {
@@ -473,60 +476,110 @@ public class InspectorFlipperPlugin implements FlipperPlugin {
} }
} }
private Touch createTouch(final int touchX, final int touchY, final boolean ax) throws Exception { private Pair<Touch, Stack<FlipperObject.Builder>> createTouch(
final FlipperArray.Builder path = new FlipperArray.Builder(); final int touchX, final int touchY, final boolean ax) throws Exception {
path.put(trackObject(mApplication)); final Stack<FlipperObject.Builder> objStack = new Stack<>();
objStack.push(new FlipperObject.Builder());
return new Touch() { final Stack<Object> nodes = new Stack<>();
int x = touchX; nodes.push(mApplication);
int y = touchY;
Object node = mApplication;
@Override final Touch touch =
public void finish() { new Touch() {
mConnection.send( int x = touchX;
ax ? "selectAX" : "select", new FlipperObject.Builder().put("path", path).build()); int y = touchY;
}
@Override
public void continueWithOffset(final int childIndex, final int offsetX, final int offsetY) {
final Touch touch = this;
new ErrorReportingRunnable(mConnection) {
@Override @Override
protected void runOrThrow() throws Exception { public void finish() {}
x -= offsetX;
y -= offsetY;
if (ax) { @Override
node = assertNotNull(descriptorForObject(node).getAXChildAt(node, childIndex)); public void continueWithOffset(
} else { final int childIndex, final int offsetX, final int offsetY) {
node = assertNotNull(descriptorForObject(node).getChildAt(node, childIndex)); final Touch touch = this;
}
path.put(trackObject(node)); new ErrorReportingRunnable(mConnection) {
final NodeDescriptor<Object> descriptor = descriptorForObject(node); @Override
protected void runOrThrow() throws Exception {
Object nextNode;
final Object currNode = nodes.peek();
x -= offsetX;
y -= offsetY;
if (ax) { if (ax) {
descriptor.axHitTest(node, touch); nextNode =
} else { assertNotNull(
descriptor.hitTest(node, touch); descriptorForObject(currNode).getAXChildAt(currNode, childIndex));
} } else {
nextNode =
assertNotNull(descriptorForObject(currNode).getChildAt(currNode, childIndex));
}
nodes.push(nextNode);
final String nodeID = trackObject(nextNode);
final NodeDescriptor<Object> descriptor = descriptorForObject(nextNode);
objStack.push(new FlipperObject.Builder());
if (ax) {
descriptor.axHitTest(nextNode, touch);
} else {
descriptor.hitTest(nextNode, touch);
}
x += offsetX;
y += offsetY;
nodes.pop();
final FlipperObject objTree = objStack.pop().build();
objStack.peek().put(nodeID, objTree);
}
}.run();
} }
}.run();
}
@Override @Override
public boolean containedIn(int l, int t, int r, int b) { public boolean containedIn(int l, int t, int r, int b) {
return x >= l && x <= r && y >= t && y <= b; return x >= l && x <= r && y >= t && y <= b;
} }
}; };
return new Pair<>(touch, objStack);
}
// This is mainly for backward compatibility
private FlipperArray getPathFromTree(FlipperObject tree) {
final FlipperArray.Builder pathBuilder = new FlipperArray.Builder();
FlipperObject subtree = tree;
Iterator<String> it = subtree.keys();
while (it.hasNext()) {
final String key = it.next();
pathBuilder.put(key);
subtree = subtree.getObject(key);
it = subtree.keys();
}
return pathBuilder.build();
} }
void hitTest(final int touchX, final int touchY) throws Exception { void hitTest(final int touchX, final int touchY) throws Exception {
final NodeDescriptor<Object> descriptor = descriptorForObject(mApplication); final NodeDescriptor<Object> descriptor = descriptorForObject(mApplication);
descriptor.hitTest(mApplication, createTouch(touchX, touchY, false)); FlipperObject treeObj;
descriptor.axHitTest(mApplication, createTouch(touchX, touchY, true));
Pair<Touch, Stack<FlipperObject.Builder>> pair = createTouch(touchX, touchY, false);
descriptor.hitTest(mApplication, pair.first);
treeObj = new FlipperObject.Builder().put(trackObject(mApplication), pair.second.pop()).build();
mConnection.send(
"select",
new FlipperObject.Builder()
.put("tree", treeObj)
.put("path", getPathFromTree(treeObj))
.build());
pair = createTouch(touchX, touchY, true);
descriptor.axHitTest(mApplication, pair.first);
treeObj = new FlipperObject.Builder().put(trackObject(mApplication), pair.second.pop()).build();
mConnection.send(
"selectAX",
new FlipperObject.Builder()
.put("tree", treeObj)
.put("path", getPathFromTree(treeObj))
.build());
} }
private void setHighlighted( private void setHighlighted(

View File

@@ -269,9 +269,20 @@ public class InspectorFlipperPluginTest {
connection.sent.get("select"), connection.sent.get("select"),
hasItem( hasItem(
new FlipperObject.Builder() new FlipperObject.Builder()
.put(
"tree",
new FlipperObject.Builder()
.put(
"com.facebook.flipper",
new FlipperObject.Builder()
.put(
"test",
new FlipperObject.Builder()
.put("3", new FlipperObject.Builder())
.put("1", new FlipperObject.Builder()))))
.put( .put(
"path", "path",
new FlipperArray.Builder().put("com.facebook.flipper").put("test").put("3")) new FlipperArray.Builder().put("com.facebook.flipper").put("test").put("1"))
.build())); .build()));
} }
@@ -391,16 +402,17 @@ public class InspectorFlipperPluginTest {
@Override @Override
public void hitTest(TestNode node, Touch touch) { public void hitTest(TestNode node, Touch touch) {
boolean finish = true;
for (int i = node.children.size() - 1; i >= 0; i--) { for (int i = node.children.size() - 1; i >= 0; i--) {
final TestNode child = node.children.get(i); final TestNode child = node.children.get(i);
final Rect bounds = child.bounds; final Rect bounds = child.bounds;
if (touch.containedIn(bounds.left, bounds.top, bounds.right, bounds.bottom)) { if (touch.containedIn(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
touch.continueWithOffset(i, bounds.left, bounds.top); touch.continueWithOffset(i, bounds.left, bounds.top);
return; finish = false;
} }
} }
touch.finish(); if (finish) touch.finish();
} }
@Override @Override