package sh.calaba.instrumentationbackend.query.ast; import static sh.calaba.instrumentationbackend.InstrumentationBackend.viewFetcher; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.antlr.runtime.tree.CommonTree; import sh.calaba.instrumentationbackend.InstrumentationBackend; import sh.calaba.instrumentationbackend.actions.webview.QueryHelper; import sh.calaba.instrumentationbackend.query.CompletedFuture; import sh.calaba.instrumentationbackend.query.antlr.UIQueryParser; import sh.calaba.org.codehaus.jackson.map.ObjectMapper; import sh.calaba.org.codehaus.jackson.type.TypeReference; import android.content.res.Resources.NotFoundException; import android.view.View; import android.webkit.WebView; public class UIQueryUtils { @SuppressWarnings({ "unchecked", "rawtypes" }) public static List subviews(Object o) { try { Method getChild = o.getClass().getMethod("getChildAt", int.class); getChild.setAccessible(true); Method getChildCount = o.getClass().getMethod("getChildCount"); getChildCount.setAccessible(true); List result = new ArrayList(8); int childCount = (Integer) getChildCount.invoke(o); for (int i=0;i result = new AtomicReference(); final AtomicReference errorResult = new AtomicReference(); InstrumentationBackend.instrumentation.runOnMainSync(new Runnable() { @SuppressWarnings("unchecked") public void run() { try { Object res = callable.call(); if (res instanceof Future) { result.set((Future) res); } else { result.set(new CompletedFuture(res)); } } catch (Exception e) { errorResult.set(e); } } }); if (result.get() == null) { throw errorResult.get(); } return result.get(); } @SuppressWarnings("rawtypes") public static Object evaluateSyncInMainThread(Callable callable) { try { return evaluateAsyncInMainThread(callable).get(10, TimeUnit.SECONDS); } catch (RuntimeException e) { throw e; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } @SuppressWarnings({ "unchecked", "rawtypes" }) public static List> mapWebViewJsonResponse(final String jsonResponse, final WebView webView) { return (List>) evaluateSyncInMainThread(new Callable() { @Override public Object call() throws Exception { List> parsedResult; try { parsedResult = new ObjectMapper().readValue( jsonResponse, new TypeReference>>() {}); for (Map data : parsedResult) { Map rect = (Map) data.get("rect"); Map updatedRect = QueryHelper.translateRectToScreenCoordinates(webView, rect); data.put("rect", updatedRect); data.put("webView", webView); } return parsedResult; } catch (Exception igored) { try { Map resultAsMap = new ObjectMapper().readValue( jsonResponse, new TypeReference() {}); //This usually happens in case of error //check this case System.out.println(resultAsMap); String errorMsg = (String) resultAsMap.get("error"); System.out.println(errorMsg); return Collections.singletonList(resultAsMap); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } } }); } public static Object parseValue(CommonTree val) { switch (val.getType()) { case UIQueryParser.STRING: { String textWithPings = val.getText(); String text = textWithPings .substring(1, textWithPings.length() - 1); text = text.replaceAll("\\\\'", "'"); return text; } case UIQueryParser.INT: return Integer.parseInt(val.getText(), 10); case UIQueryParser.BOOL: { String text = val.getText(); return Boolean.parseBoolean(text); } case UIQueryParser.NIL: return null; default: throw new IllegalArgumentException("Unable to parse value type:" + val.getType() + " text " + val.getText()); } } }