@ChromeDevtoolsMethod @SuppressWarnings("unused") public JsonRpcResult executeSQL(JsonRpcPeer peer, JSONObject params) { Timber.d("executeSQL: %s", String.valueOf(params)); ExecuteSQLResponse response = new ExecuteSQLResponse(); try { ExecuteSQLRequest request = mObjectMapper.convertValue(params, ExecuteSQLRequest.class); return mCouchbasePeerManager.executeSQL(request.databaseId, request.query); } catch (Exception e) { Timber.e(e.toString()); Error error = new Error(); error.code = 0; error.message = e.getMessage(); response.sqlError = error; return response; } }
@ChromeDevtoolsMethod public void highlightNode(JsonRpcPeer peer, JSONObject params) { final HighlightNodeRequest request = mObjectMapper.convertValue(params, HighlightNodeRequest.class); if (request.nodeId == null) { LogUtil.w("DOM.highlightNode was not given a nodeId; JS objectId is not supported"); return; } final RGBAColor contentColor = request.highlightConfig.contentColor; if (contentColor == null) { LogUtil.w("DOM.highlightNode was not given a color to highlight with"); return; } mDocument.postAndWait(new Runnable() { @Override public void run() { Object element = mDocument.getElementForNodeId(request.nodeId); if (element != null) { mDocument.highlightElement(element, contentColor.getColor()); } } }); }
@ChromeDevtoolsMethod public void setAttributesAsText(JsonRpcPeer peer, JSONObject params) { final SetAttributesAsTextRequest request = mObjectMapper.convertValue( params, SetAttributesAsTextRequest.class); mDocument.postAndWait(new Runnable() { @Override public void run() { Object element = mDocument.getElementForNodeId(request.nodeId); if (element != null) { mDocument.setAttributesAsText(element, request.text); } } }); }
@ChromeDevtoolsMethod public GetSearchResultsResponse getSearchResults(JsonRpcPeer peer, JSONObject params) { final GetSearchResultsRequest request = mObjectMapper.convertValue( params, GetSearchResultsRequest.class); if (request.searchId == null) { LogUtil.w("searchId may not be null"); return null; } final List<Integer> results = mSearchResults.get(request.searchId); if (results == null) { LogUtil.w("\"" + request.searchId + "\" is not a valid reference to a search result"); return null; } final List<Integer> resultsRange = results.subList(request.fromIndex, request.toIndex); final GetSearchResultsResponse response = new GetSearchResultsResponse(); response.nodeIds = resultsRange; return response; }
@ChromeDevtoolsMethod public JsonRpcResult getDatabaseTableNames(JsonRpcPeer peer, JSONObject params) throws JsonRpcException { GetDatabaseTableNamesRequest request = mObjectMapper.convertValue(params, GetDatabaseTableNamesRequest.class); String databaseId = request.databaseId; DatabaseDescriptorHolder holder = mPeerListener.getDatabaseDescriptorHolder(databaseId); try { GetDatabaseTableNamesResponse response = new GetDatabaseTableNamesResponse(); response.tableNames = holder.driver.getTableNames(holder.descriptor); return response; } catch (SQLiteException e) { throw new JsonRpcException( new JsonRpcError( JsonRpcError.ErrorCode.INVALID_REQUEST, e.toString(), null /* data */)); } }
@ChromeDevtoolsMethod public JsonRpcResult getDOMStorageItems(JsonRpcPeer peer, JSONObject params) throws JSONException { StorageId storage = mObjectMapper.convertValue( params.getJSONObject("storageId"), StorageId.class); ArrayList<List<String>> entries = new ArrayList<List<String>>(); String prefTag = storage.securityOrigin; if (storage.isLocalStorage) { SharedPreferences prefs = mContext.getSharedPreferences(prefTag, Context.MODE_PRIVATE); for (Map.Entry<String, ?> prefsEntry : prefs.getAll().entrySet()) { ArrayList<String> entry = new ArrayList<String>(2); entry.add(prefsEntry.getKey()); entry.add(SharedPreferencesHelper.valueToString(prefsEntry.getValue())); entries.add(entry); } } GetDOMStorageItemsResult result = new GetDOMStorageItemsResult(); result.entries = entries; return result; }
@ChromeDevtoolsMethod public JsonRpcResult getDatabaseTableNames(JsonRpcPeer peer, JSONObject params) { final SharedRealm realm = getRealm( objectMapper.convertValue(params, GetDatabaseTableNamesRequest.class).databaseId); final int size = (int) realm.size(); final List<String> tableNames = new ArrayList<>(size); for (int i = 0; i < size; ++i) { tableNames.add(realm.getTableName(i)); } final GetDatabaseTableNamesResponse response = new GetDatabaseTableNamesResponse(); response.tableNames = tableNames; return response; }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public JsonRpcResult getDatabaseTableNames(JsonRpcPeer peer, JSONObject params) { GetDatabaseTableNamesRequest request = objectMapper.convertValue(params, GetDatabaseTableNamesRequest.class); GetDatabaseTableNamesResponse response = new GetDatabaseTableNamesResponse(); response.tableNames = realmPeerManager.getDatabaseTableNames(request.databaseId, withMetaTables); return response; }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public JsonRpcResult getDatabaseTableNames(JsonRpcPeer peer, JSONObject params) { Timber.d("getAllDocumentIds: %s", String.valueOf(params)); GetDatabaseTableNamesRequest request = mObjectMapper.convertValue(params, GetDatabaseTableNamesRequest.class); GetDatabaseTableNamesResponse response = new GetDatabaseTableNamesResponse(); response.tableNames = mCouchbasePeerManager.getAllDocumentIds(request.databaseId); return response; }
@ChromeDevtoolsMethod public JsonRpcResult getResourceTree(JsonRpcPeer peer, JSONObject params) { // The DOMStorage module expects one key/value store per "security origin" which has a 1:1 // relationship with resource tree frames. List<String> prefsTags = SharedPreferencesHelper.getSharedPreferenceTags(mContext); Iterator<String> prefsTagsIter = prefsTags.iterator(); FrameResourceTree tree = createSimpleFrameResourceTree( "1", null /* parentId */, "Stetho", prefsTagsIter.hasNext() ? prefsTagsIter.next() : ""); if (tree.childFrames == null) { tree.childFrames = new ArrayList<FrameResourceTree>(); } int nextChildFrameId = 1; while (prefsTagsIter.hasNext()) { String frameId = "1." + (nextChildFrameId++); String prefsTag = prefsTagsIter.next(); FrameResourceTree child = createSimpleFrameResourceTree( frameId, "1", "Child #" + frameId, prefsTag); tree.childFrames.add(child); } GetResourceTreeParams resultParams = new GetResourceTreeParams(); resultParams.frameTree = tree; return resultParams; }
@ChromeDevtoolsMethod public void startScreencast(final JsonRpcPeer peer, JSONObject params) { final StartScreencastRequest request = mObjectMapper.convertValue( params, StartScreencastRequest.class); if (mScreencastDispatcher == null) { mScreencastDispatcher = new ScreencastDispatcher(); mScreencastDispatcher.startScreencast(peer, request); } }
@ChromeDevtoolsMethod public void stopScreencast(JsonRpcPeer peer, JSONObject params) { if (mScreencastDispatcher != null) { mScreencastDispatcher.stopScreencast(); mScreencastDispatcher = null; } }
@ChromeDevtoolsMethod public JsonRpcResult getDocument(JsonRpcPeer peer, JSONObject params) { final GetDocumentResponse result = new GetDocumentResponse(); result.root = mDocument.postAndWait(new UncheckedCallable<Node>() { @Override public Node call() { Object element = mDocument.getRootElement(); return createNodeForElement(element, mDocument.getDocumentView(), null); } }); return result; }
@ChromeDevtoolsMethod public void hideHighlight(JsonRpcPeer peer, JSONObject params) { mDocument.postAndWait(new Runnable() { @Override public void run() { mDocument.hideHighlight(); } }); }
@ChromeDevtoolsMethod public ResolveNodeResponse resolveNode(JsonRpcPeer peer, JSONObject params) throws JsonRpcException { final ResolveNodeRequest request = mObjectMapper.convertValue(params, ResolveNodeRequest.class); final Object element = mDocument.postAndWait(new UncheckedCallable<Object>() { @Override public Object call() { return mDocument.getElementForNodeId(request.nodeId); } }); if (element == null) { throw new JsonRpcException( new JsonRpcError( JsonRpcError.ErrorCode.INVALID_PARAMS, "No known nodeId=" + request.nodeId, null /* data */)); } int mappedObjectId = Runtime.mapObject(peer, element); Runtime.RemoteObject remoteObject = new Runtime.RemoteObject(); remoteObject.type = Runtime.ObjectType.OBJECT; remoteObject.subtype = Runtime.ObjectSubType.NODE; remoteObject.className = element.getClass().getName(); remoteObject.value = null; // not a primitive remoteObject.description = null; // not sure what this does... remoteObject.objectId = String.valueOf(mappedObjectId); ResolveNodeResponse response = new ResolveNodeResponse(); response.object = remoteObject; return response; }
@ChromeDevtoolsMethod public void setInspectModeEnabled(JsonRpcPeer peer, JSONObject params) { final SetInspectModeEnabledRequest request = mObjectMapper.convertValue( params, SetInspectModeEnabledRequest.class); mDocument.postAndWait(new Runnable() { @Override public void run() { mDocument.setInspectModeEnabled(request.enabled); } }); }
@ChromeDevtoolsMethod public PerformSearchResponse performSearch(JsonRpcPeer peer, final JSONObject params) { final PerformSearchRequest request = mObjectMapper.convertValue( params, PerformSearchRequest.class); final ArrayListAccumulator<Integer> resultNodeIds = new ArrayListAccumulator<>(); mDocument.postAndWait(new Runnable() { @Override public void run() { mDocument.findMatchingElements(request.query, resultNodeIds); } }); // Each search action has a unique ID so that // it can be queried later. final String searchId = String.valueOf(mResultCounter.getAndIncrement()); mSearchResults.put(searchId, resultNodeIds); final PerformSearchResponse response = new PerformSearchResponse(); response.searchId = searchId; response.resultCount = resultNodeIds.size(); return response; }
@ChromeDevtoolsMethod public void discardSearchResults(JsonRpcPeer peer, JSONObject params) { final DiscardSearchResultsRequest request = mObjectMapper.convertValue( params, DiscardSearchResultsRequest.class); if (request.searchId != null) { mSearchResults.remove(request.searchId); } }
@ChromeDevtoolsMethod public void removeDOMStorageItem(JsonRpcPeer peer, JSONObject params) throws JSONException { StorageId storage = mObjectMapper.convertValue( params.getJSONObject("storageId"), StorageId.class); String key = params.getString("key"); if (storage.isLocalStorage) { SharedPreferences prefs = mContext.getSharedPreferences( storage.securityOrigin, Context.MODE_PRIVATE); prefs.edit().remove(key).apply(); } }
@ChromeDevtoolsMethod public JsonRpcResult getComputedStyleForNode(JsonRpcPeer peer, JSONObject params) { final GetComputedStyleForNodeRequest request = mObjectMapper.convertValue( params, GetComputedStyleForNodeRequest.class); final GetComputedStyleForNodeResult result = new GetComputedStyleForNodeResult(); result.computedStyle = new ArrayList<>(); mDocument.postAndWait(new Runnable() { @Override public void run() { Object element = mDocument.getElementForNodeId(request.nodeId); if (element == null) { LogUtil.e("Tried to get the style of an element that does not exist, using nodeid=" + request.nodeId); return; } mDocument.getElementComputedStyles( element, new ComputedStyleAccumulator() { @Override public void store(String name, String value) { final CSSComputedStyleProperty property = new CSSComputedStyleProperty(); property.name = name; property.value = value; result.computedStyle.add(property); } }); } }); return result; }
@ChromeDevtoolsMethod public CallFunctionOnResponse callFunctionOn(JsonRpcPeer peer, JSONObject params) throws JsonRpcException { CallFunctionOnRequest args = mObjectMapper.convertValue(params, CallFunctionOnRequest.class); Session session = getSession(peer); Object object = session.getObjectOrThrow(args.objectId); // The DevTools UI thinks it can run arbitrary JavaScript against us in order to figure out // the class structure of an object. That obviously won't fly, and there's no way to // translate without building a crude JavaScript parser so let's just go ahead and guess // what this function does by name. if (!args.functionDeclaration.startsWith("function protoList(")) { throw new JsonRpcException( new JsonRpcError( JsonRpcError.ErrorCode.INTERNAL_ERROR, "Expected protoList, got: " + args.functionDeclaration, null /* data */)); } // Since this is really a function call we have to create this fake object to hold the // "result" of the function. ObjectProtoContainer objectContainer = new ObjectProtoContainer(object); RemoteObject result = new RemoteObject(); result.type = ObjectType.OBJECT; result.subtype = ObjectSubType.NODE; result.className = object.getClass().getName(); result.description = getPropertyClassName(object); result.objectId = String.valueOf(session.getObjects().putObject(objectContainer)); CallFunctionOnResponse response = new CallFunctionOnResponse(); response.result = result; response.wasThrown = false; return response; }
/** * Determines if the method is a {@link ChromeDevtoolsMethod}, and validates accordingly * if it is. * * @throws IllegalArgumentException Thrown if it is a {@link ChromeDevtoolsMethod} but * it otherwise fails to satisfy requirements. */ private static boolean isDevtoolsMethod(Method method) throws IllegalArgumentException { if (!method.isAnnotationPresent(ChromeDevtoolsMethod.class)) { return false; } else { Class<?> args[] = method.getParameterTypes(); String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName(); Util.throwIfNot(args.length == 2, "%s: expected 2 args, got %s", methodName, args.length); Util.throwIfNot(args[0].equals(JsonRpcPeer.class), "%s: expected 1st arg of JsonRpcPeer, got %s", methodName, args[0].getName()); Util.throwIfNot(args[1].equals(JSONObject.class), "%s: expected 2nd arg of JSONObject, got %s", methodName, args[1].getName()); Class<?> returnType = method.getReturnType(); if (!returnType.equals(void.class)) { Util.throwIfNot(JsonRpcResult.class.isAssignableFrom(returnType), "%s: expected JsonRpcResult return type, got %s", methodName, returnType.getName()); } return true; } }
@ChromeDevtoolsMethod public void enable(JsonRpcPeer peer, JSONObject params) { peerManager.addPeer(peer); }
@ChromeDevtoolsMethod public void disable(JsonRpcPeer peer, JSONObject params) { peerManager.removePeer(peer); }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public void enable(JsonRpcPeer peer, JSONObject params) { realmPeerManager.addPeer(peer); }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public void disable(JsonRpcPeer peer, JSONObject params) { realmPeerManager.removePeer(peer); }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public void enable(JsonRpcPeer peer, JSONObject params) { Timber.d("Enable Peer: %s", String.valueOf(params)); mCouchbasePeerManager.addPeer(peer); }
@ChromeDevtoolsMethod @SuppressWarnings("unused") public void disable(JsonRpcPeer peer, JSONObject params) { Timber.d("Disable Peer: %s", String.valueOf(params)); mCouchbasePeerManager.removePeer(peer); }
@ChromeDevtoolsMethod public JsonRpcResult canInspectWorkers(JsonRpcPeer peer, JSONObject params) { return new SimpleBooleanResult(true); }
@ChromeDevtoolsMethod public void enable(JsonRpcPeer peer, JSONObject params) { notifyExecutionContexts(peer); sendWelcomeMessage(peer); }
@ChromeDevtoolsMethod public void disable(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public JsonRpcResult canScreencast(JsonRpcPeer peer, JSONObject params) { return new SimpleBooleanResult(true); }
@ChromeDevtoolsMethod public JsonRpcResult hasTouchInputs(JsonRpcPeer peer, JSONObject params) { return new SimpleBooleanResult(false); }
@ChromeDevtoolsMethod public void setDeviceMetricsOverride(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public void clearDeviceOrientationOverride(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public void screencastFrameAck(JsonRpcPeer peer, JSONObject params) { // Nothing to do here, just need to make sure Chrome doesn't get an error that this method // isn't implemented }
@ChromeDevtoolsMethod public void clearGeolocationOverride(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public void setTouchEmulationEnabled(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public void setEmulatedMedia(JsonRpcPeer peer, JSONObject params) { }
@ChromeDevtoolsMethod public void setShowViewportSizeOnResize(JsonRpcPeer peer, JSONObject params) { }