From 8086eac30b939adde43080f9026bbd54cb156fad Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Mon, 20 Jun 2011 14:17:16 -0700 Subject: Added view introspection to ChimpChat and MonkeyRunner Change-Id: I0e44f6d2c51c99cb0409087a77e2916b630051da --- .../src/com/android/chimpchat/ChimpManager.java | 123 ++++++++++++- .../com/android/chimpchat/adb/AdbChimpDevice.java | 42 +++++ chimpchat/src/com/android/chimpchat/core/By.java | 46 +++++ .../com/android/chimpchat/core/ChimpException.java | 22 +++ .../src/com/android/chimpchat/core/ChimpRect.java | 105 +++++++++++ .../src/com/android/chimpchat/core/ChimpView.java | 201 +++++++++++++++++++++ .../com/android/chimpchat/core/IChimpDevice.java | 36 +++- .../src/com/android/chimpchat/core/IChimpView.java | 92 ++++++++++ .../com/android/chimpchat/core/IMultiSelector.java | 29 +++ .../src/com/android/chimpchat/core/ISelector.java | 29 +++ .../android/chimpchat/core/MultiSelectorText.java | 75 ++++++++ .../com/android/chimpchat/core/PhysicalButton.java | 8 +- .../chimpchat/core/SelectorAccessibilityIds.java | 48 +++++ .../src/com/android/chimpchat/core/SelectorId.java | 42 +++++ .../src/com/android/monkeyrunner/MonkeyDevice.java | 83 ++++++++- .../src/com/android/monkeyrunner/MonkeyRect.java | 85 +++++++++ .../src/com/android/monkeyrunner/MonkeyView.java | 167 +++++++++++++++++ 17 files changed, 1210 insertions(+), 23 deletions(-) create mode 100644 chimpchat/src/com/android/chimpchat/core/By.java create mode 100644 chimpchat/src/com/android/chimpchat/core/ChimpException.java create mode 100644 chimpchat/src/com/android/chimpchat/core/ChimpRect.java create mode 100644 chimpchat/src/com/android/chimpchat/core/ChimpView.java create mode 100644 chimpchat/src/com/android/chimpchat/core/IChimpView.java create mode 100644 chimpchat/src/com/android/chimpchat/core/IMultiSelector.java create mode 100644 chimpchat/src/com/android/chimpchat/core/ISelector.java create mode 100644 chimpchat/src/com/android/chimpchat/core/MultiSelectorText.java create mode 100644 chimpchat/src/com/android/chimpchat/core/SelectorAccessibilityIds.java create mode 100644 chimpchat/src/com/android/chimpchat/core/SelectorId.java create mode 100644 monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java create mode 100644 monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java diff --git a/chimpchat/src/com/android/chimpchat/ChimpManager.java b/chimpchat/src/com/android/chimpchat/ChimpManager.java index c68b7df..475c7c1 100644 --- a/chimpchat/src/com/android/chimpchat/ChimpManager.java +++ b/chimpchat/src/com/android/chimpchat/ChimpManager.java @@ -16,9 +16,13 @@ */ package com.android.chimpchat; -import com.google.common.collect.Lists; - +import com.android.chimpchat.core.IChimpView; import com.android.chimpchat.core.PhysicalButton; +import com.android.chimpchat.core.ChimpException; +import com.android.chimpchat.core.ChimpRect; +import com.android.chimpchat.core.ChimpView; + +import com.google.common.collect.Lists; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -26,8 +30,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; +import java.net.SocketException; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; @@ -58,6 +65,16 @@ public class ChimpManager { monkeyReader = new BufferedReader(new InputStreamReader(monkeySocket.getInputStream())); } + /* Ensure that everything gets shutdown properly */ + protected void finalize() throws Throwable { + try { + quit(); + } finally { + close(); + super.finalize(); + } + } + /** * Send a touch down event at the specified location. * @@ -158,6 +175,7 @@ public class ChimpManager { * * @param command the monkey command to send to the device * @return the (unparsed) response returned from the monkey. + * @throws IOException on error communicating with the device */ private String sendMonkeyEventAndGetResponse(String command) throws IOException { command = command.trim(); @@ -209,6 +227,7 @@ public class ChimpManager { * * @param command the monkey command to send to the device * @return true on success. + * @throws IOException on error communicating with the device */ private boolean sendMonkeyEvent(String command) throws IOException { synchronized (this) { @@ -243,6 +262,7 @@ public class ChimpManager { * * @param name name of static variable to get * @return the value of the variable, or null if there was an error + * @throws IOException on error communicating with the device */ public String getVariable(String name) throws IOException { synchronized (this) { @@ -255,7 +275,9 @@ public class ChimpManager { } /** - * Function to get the list of static variables from the device. + * Function to get the list of variables from the device. + * @return the list of variables as a collection of strings + * @throws IOException on error communicating with the device */ public Collection listVariable() throws IOException { synchronized (this) { @@ -270,7 +292,7 @@ public class ChimpManager { /** * Tells the monkey that we are done for this session. - * @throws IOException + * @throws IOException on error communicating with the device */ public void done() throws IOException { // this command just drops the connection, so handle it here @@ -281,12 +303,17 @@ public class ChimpManager { /** * Tells the monkey that we are done forever. - * @throws IOException + * @throws IOException on error communicating with the device */ public void quit() throws IOException { // this command drops the connection, so handle it here synchronized (this) { - sendMonkeyEventAndGetResponse("quit"); + try { + sendMonkeyEventAndGetResponse("quit"); + } catch (SocketException e) { + // flush was called after the call had been written, so it tried flushing to a + // broken pipe. + } } } @@ -296,7 +323,6 @@ public class ChimpManager { * @param x the x coordinate of where to click * @param y the y coordinate of where to click * @return success or not - * @throws IOException * @throws IOException on error communicating with the device */ public boolean tap(int x, int y) throws IOException { @@ -308,7 +334,7 @@ public class ChimpManager { * * @param text the string to type * @return success - * @throws IOException + * @throws IOException on error communicating with the device */ public boolean type(String text) throws IOException { // The network protocol can't handle embedded line breaks, so we have to handle it @@ -336,7 +362,7 @@ public class ChimpManager { * * @param keyChar the character to type. * @return success - * @throws IOException + * @throws IOException on error communicating with the device */ public boolean type(char keyChar) throws IOException { return type(Character.toString(keyChar)); @@ -344,9 +370,86 @@ public class ChimpManager { /** * Wake the device up from sleep. - * @throws IOException + * @throws IOException on error communicating with the device */ public void wake() throws IOException { sendMonkeyEvent("wake"); } + + + /** + * Retrieves the list of view ids from the current application. + * @return the list of view ids as a collection of strings + * @throws IOException on error communicating with the device + */ + public Collection listViewIds() throws IOException { + synchronized (this) { + String response = sendMonkeyEventAndGetResponse("listviews"); + if (!parseResponseForSuccess(response)) { + Collections.emptyList(); + } + String extras = parseResponseForExtra(response); + return Lists.newArrayList(extras.split(" ")); + } + } + + /** + * Queries the on-screen view with the given id and returns the response. + * It's up to the calling method to parse the returned String. + * @param idType The type of ID to query the view by + * @param id The view id of the view + * @param query the query + * @return the response from the query + * @throws IOException on error communicating with the device + */ + public String queryView(String idType, List ids, String query) throws IOException { + StringBuilder monkeyCommand = new StringBuilder("queryview " + idType + " "); + for(String id : ids) { + monkeyCommand.append(id).append(" "); + } + monkeyCommand.append(query); + synchronized (this) { + String response = sendMonkeyEventAndGetResponse(monkeyCommand.toString()); + if (!parseResponseForSuccess(response)) { + throw new ChimpException(parseResponseForExtra(response)); + } + return parseResponseForExtra(response); + } + } + + /** + * Returns the current root view of the device. + * @return the root view of the device + */ + public IChimpView getRootView() throws IOException { + synchronized(this) { + String response = sendMonkeyEventAndGetResponse("getrootview"); + String extra = parseResponseForExtra(response); + List ids = Arrays.asList(extra.split(" ")); + if (!parseResponseForSuccess(response) || ids.size() != 2) { + throw new ChimpException(extra); + } + ChimpView root = new ChimpView(ChimpView.ACCESSIBILITY_IDS, ids); + root.setManager(this); + return root; + } + } + + /** + * Queries the device for a list of views with the given + * @return A string containing the accessibility ids of the views with the given text + */ + public String getViewsWithText(String text) throws IOException { + synchronized(this) { + // Monkey has trouble parsing a single word in quotes + if (text.split(" ").length > 1) { + text = "\"" + text + "\""; + } + String response = sendMonkeyEventAndGetResponse("getviewswithtext " + text); + if (!parseResponseForSuccess(response)) { + throw new ChimpException(parseResponseForExtra(response)); + } + return parseResponseForExtra(response); + } + } } diff --git a/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java b/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java index cfc0755..d4513d1 100644 --- a/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java +++ b/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java @@ -27,8 +27,13 @@ import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import com.android.chimpchat.ChimpManager; import com.android.chimpchat.adb.LinearInterpolator.Point; +import com.android.chimpchat.core.ChimpRect; import com.android.chimpchat.core.IChimpImage; import com.android.chimpchat.core.IChimpDevice; +import com.android.chimpchat.core.IChimpView; +import com.android.chimpchat.core.IMultiSelector; +import com.android.chimpchat.core.ISelector; +import com.android.chimpchat.core.PhysicalButton; import com.android.chimpchat.core.TouchPressType; import com.android.chimpchat.hierarchyviewer.HierarchyViewer; @@ -36,6 +41,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -328,6 +334,11 @@ public class AdbChimpDevice implements IChimpDevice { } @Override + public void press(PhysicalButton key, TouchPressType type) { + press(key.getKeyName(), type); + } + + @Override public void type(String string) { try { manager.type(string); @@ -566,4 +577,35 @@ public class AdbChimpDevice implements IChimpDevice { } }); } + + + @Override + public Collection getViewIdList() { + try { + return manager.listViewIds(); + } catch(IOException e) { + LOG.log(Level.SEVERE, "Error retrieving view IDs", e); + return new ArrayList(); + } + } + + @Override + public IChimpView getView(ISelector selector) { + return selector.getView(manager); + } + + @Override + public Collection getViews(IMultiSelector selector) { + return selector.getViews(manager); + } + + @Override + public IChimpView getRootView() { + try { + return manager.getRootView(); + } catch (IOException e) { + LOG.log(Level.SEVERE, "Error retrieving root view"); + return null; + } + } } diff --git a/chimpchat/src/com/android/chimpchat/core/By.java b/chimpchat/src/com/android/chimpchat/core/By.java new file mode 100644 index 0000000..364eab4 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/By.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +/** + * A class that lets you select objects based on different criteria. + * It operates similar to WebDriver's By class. + */ +public class By { + /** + * A method to let you select items by id. + * @param id The string id of the object you want + * @return a selector that will select the appropriate item by id + */ + public static ISelector id(String id) { + return new SelectorId(id); + } + + /** + * A method that lets you select items by accessibility ids. + * @param windowId the windowId of the object you want to select. + * @param accessibilityId the accessibility id of the object you want to select + * @return a selector that will select the appropriate object by its accessibility ids. + */ + public static ISelector accessibilityIds(int windowId, int accessibilityId){ + return new SelectorAccessibilityIds(windowId, accessibilityId); + } + + public static IMultiSelector text(String searchText) { + return new MultiSelectorText(searchText); + } +} diff --git a/chimpchat/src/com/android/chimpchat/core/ChimpException.java b/chimpchat/src/com/android/chimpchat/core/ChimpException.java new file mode 100644 index 0000000..9546595 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/ChimpException.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.chimpchat.core; + +public class ChimpException extends RuntimeException { + public ChimpException(String s) { + super(s); + } +} diff --git a/chimpchat/src/com/android/chimpchat/core/ChimpRect.java b/chimpchat/src/com/android/chimpchat/core/ChimpRect.java new file mode 100644 index 0000000..a86c23d --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/ChimpRect.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +/** + * A class for holding information about view locations + */ +public class ChimpRect { + public int left; + public int top; + public int right; + public int bottom; + + /** + * Creates an empty ChimpRect object. All coordinates are initialized to 0. + */ + public ChimpRect() {} + + /** + * Create a new ChimpRect with the given coordinates. + * @param left The X coordinate of the left side of the rectagle + * @param top The Y coordinate of the top of the rectangle + * @param right The X coordinate of the right side of the rectagle + * @param bottom The Y coordinate of the bottom of the rectangle + */ + public ChimpRect(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /** + * A comparison method to determine if the object is equivalent to other ChimpRects. + * @param obj The object to compare it to + * @return True if the object is an equivalent rectangle, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof ChimpRect){ + ChimpRect r = (ChimpRect) obj; + if (r != null) { + return left == r.left && top == r.top && right == r.right + && bottom == r.bottom; + } + } + return false; + } + + /** + * The width of the ChimpRect + * @return the width of the rectangle + */ + public int getWidth() { + return right-left; + } + + /** + * The height of the ChimpRect + * @return the height of the rectangle + */ + public int getHeight() { + return bottom-top; + } + + /** + * Returns a 2 item int array with the x, y coordinates of the center of the ChimpRect. + * @return a 2 item int array. The first item is the x value of the center of the ChimpRect and + * the second item is the y value. + */ + public int[] getCenter() { + int[] center = new int[2]; + center[0] = left + getWidth() / 2; + center[1] = top + getHeight() / 2; + return center; + } + + /** + * Returns a representation of the rectangle in string form + * @return a string representation of the rectangle + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ChimpRect "); + sb.append("top: ").append(top).append(" "); + sb.append("right: ").append(right).append(" "); + sb.append("bottom: ").append(bottom).append(" "); + sb.append("left: ").append(left).append(" "); + return sb.toString(); + } +} diff --git a/chimpchat/src/com/android/chimpchat/core/ChimpView.java b/chimpchat/src/com/android/chimpchat/core/ChimpView.java new file mode 100644 index 0000000..c1c5be3 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/ChimpView.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import com.google.common.collect.Lists; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/* A class for querying a view object by its id */ +public class ChimpView implements IChimpView { + private static final Logger LOG = Logger.getLogger(ChimpView.class.getName()); + public static final String ACCESSIBILITY_IDS = "accessibilityids"; + public static final String VIEW_ID = "viewid"; + + private String viewType; + private List ids; + private ChimpManager manager; + + public ChimpView(String viewType, List ids) { + this.viewType = viewType; + this.ids = ids; + } + + public void setManager(ChimpManager manager) { + this.manager = manager; + } + + private String queryView(String query) { + try { + return manager.queryView(viewType, ids, query); + } catch(IOException e) { + LOG.log(Level.SEVERE, "Error querying view: " + e.getMessage()); + return ""; + } + } + + /** + * Get the coordinates for the view with the given id. + * @return a ChimpRect object with the coordinates for the corners of the view + */ + public ChimpRect getLocation() { + List result = Lists.newArrayList(queryView("getlocation").split(" ")); + if (result.size() == 4) { + try { + int left = Integer.parseInt(result.get(0)); + int top = Integer.parseInt(result.get(1)); + int width = Integer.parseInt(result.get(2)); + int height = Integer.parseInt(result.get(3)); + return new ChimpRect(left, top, left+width, top+height); + } catch (NumberFormatException e) { + return new ChimpRect(); + } + } + return new ChimpRect(); + } + + /** + * Retrieve the text contained by the view + * @return the text contained by the view + */ + public String getText() { + return queryView("gettext"); + } + + /** + * Get the class of the view + * @return the class name of the view + */ + public String getViewClass(){ + return queryView("getclass"); + } + + /** + * Get the checked status of the view. + * @return true if the view is checked, false otherwise + */ + public boolean getChecked(){ + return Boolean.valueOf(queryView("getchecked").trim()); + } + + /** + * Get whether the view is enabled or not. + * @return true if the view is enabled, false otherwise + */ + public boolean getEnabled(){ + return Boolean.valueOf(queryView("getenabled").trim()); + } + + /** + * Get the selected status of the view. + * @return true if the view is selected, false otherwise + */ + public boolean getSelected(){ + return Boolean.valueOf(queryView("getselected").trim()); + } + + /** + * Set the selected status of the view. + * @param selected the select status to set for the view + */ + public void setSelected(boolean selected) { + queryView("setselected " + selected); + } + + /** + * Get the focused status of the view. + * @return true if the view is focused, false otherwise + */ + public boolean getFocused(){ + return Boolean.valueOf(queryView("getselected").trim()); + } + + /** + * Set the focused status of the view. + * @param focused the focus status to set for the view + */ + public void setFocused(boolean focused) { + queryView("setfocused " + focused); + } + + /** + * Get the parent of the view. + * @return the parent of the view + */ + public IChimpView getParent() { + List results = Lists.newArrayList(queryView("getparent").split(" ")); + if (results.size() == 2) { + ChimpView parent = new ChimpView(ChimpView.ACCESSIBILITY_IDS, results); + parent.setManager(manager); + return parent; + } + return null; + } + + /** + * Gets the children of the view. + * @return the children of the view as a List of IChimpViews + */ + public List getChildren() { + List results = Lists.newArrayList(queryView("getchildren").split(" ")); + /* We make sure this has an even number of results because we don't necessarily know how + * many children there are, but we know all children will return a pair of accessibility ids + */ + if (results.size() % 2 == 0) { + List children = new ArrayList(); + for (int i = 0; i < results.size()/2; i++) { + List ids = Lists.newArrayList(results.get(2 * i), results.get(2 * i + 1)); + ChimpView child = new ChimpView(ChimpView.ACCESSIBILITY_IDS, ids); + child.setManager(manager); + children.add(child); + } + return children; + } + return new ArrayList(); + } + + + /** + * Gets the accessibility ids of the current view + * @return the accessibility ids of the current view. Its returned as a two-item array of ints + * with first int being the window id, and the second int being the accessibility view id. + */ + public int[] getAccessibilityIds() { + List results = Lists.newArrayList(queryView("getaccessibilityids").split(" ")); + if (results.size() == 2) { + int[] accessibilityIds = new int[2]; + try { + accessibilityIds[0] = Integer.parseInt(results.get(0)); + accessibilityIds[1] = Integer.parseInt(results.get(1)); + return accessibilityIds; + } catch (NumberFormatException e) { + LOG.log(Level.SEVERE, "Error retrieving accesibility ids: " + e.getMessage()); + } + } + int[] empty = {0,0}; + return empty; + } + +} diff --git a/chimpchat/src/com/android/chimpchat/core/IChimpDevice.java b/chimpchat/src/com/android/chimpchat/core/IChimpDevice.java index 03dc09d..14b58a7 100644 --- a/chimpchat/src/com/android/chimpchat/core/IChimpDevice.java +++ b/chimpchat/src/com/android/chimpchat/core/IChimpDevice.java @@ -20,6 +20,7 @@ import com.android.chimpchat.ChimpManager; import com.android.chimpchat.hierarchyviewer.HierarchyViewer; import java.util.Collection; +import java.util.List; import java.util.Map; import javax.annotation.Nullable; @@ -94,13 +95,20 @@ public interface IChimpDevice { /** * Perform a press of a given type using a given key. * - * TODO: define standard key names in a separate class or enum - * * @param keyName the name of the key to use * @param type the type of press to perform */ void press(String keyName, TouchPressType type); + + /** + * Perform a press of a given type using a given key. + * + * @param key the key to press + * @param type the type of press to perform + */ + void press(PhysicalButton key, TouchPressType type); + /** * Perform a drag from one one location to another * @@ -201,4 +209,28 @@ public interface IChimpDevice { * Wake up the screen on the device. */ void wake(); + + /** + * List the possible view ID strings from the current applications resource file + * @return the list of view id strings + */ + Collection getViewIdList(); + + /** + * Retrieve the view object for the view with the given id. + * @return a view object for the view with the given id + */ + IChimpView getView(ISelector selector); + + /** + * Retrive the root view object. + * @return the root view object. + */ + IChimpView getRootView(); + + /** + * Retrieves the view objects that match the given selector + * @return A list of views that match the given selector + */ + Collection getViews(IMultiSelector selector); } diff --git a/chimpchat/src/com/android/chimpchat/core/IChimpView.java b/chimpchat/src/com/android/chimpchat/core/IChimpView.java new file mode 100644 index 0000000..177271a --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/IChimpView.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import java.util.List; + +/** + * An interface for view introspection. + */ +public interface IChimpView { + + /** + * Set the manager for this view to communicate through. + */ + void setManager(ChimpManager manager); + + /** + * Obtain the class of the view as a string + */ + String getViewClass(); + + /** + * Obtain the text contained in the view + */ + String getText(); + + /** + * Obtain the location of the view on the device screen + */ + ChimpRect getLocation(); + + /** + * Obtain the checked status of this view. + */ + boolean getChecked(); + + /** + * Obtain the enabled status of this view. + */ + boolean getEnabled(); + + /** + * Obtain the selected status of this view. + */ + boolean getSelected(); + + /** + * Set the selected status of the this view + */ + void setSelected(boolean selected); + + /** + * Obtain the focused status of this view. + */ + boolean getFocused(); + + /** + * Set the focused status of this view. + */ + void setFocused(boolean focused); + + /** + * Retrieve the parent of this view if it has one. + */ + IChimpView getParent(); + + /** + * Get the children of this view as a list of IChimpViews. + */ + List getChildren(); + + /** + * Get the accessibility ids of this view. + */ + int[] getAccessibilityIds(); +} diff --git a/chimpchat/src/com/android/chimpchat/core/IMultiSelector.java b/chimpchat/src/com/android/chimpchat/core/IMultiSelector.java new file mode 100644 index 0000000..43e67fb --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/IMultiSelector.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import java.util.Collection; + +/** An interface for selectors that select more than one item */ +public interface IMultiSelector { + /** + * A method that allows you to get a list of views based on the given selector type + */ + Collection getViews(ChimpManager manager); +} diff --git a/chimpchat/src/com/android/chimpchat/core/ISelector.java b/chimpchat/src/com/android/chimpchat/core/ISelector.java new file mode 100644 index 0000000..c3db2a5 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/ISelector.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +/** + * An interface for selectors + */ +public interface ISelector { + /** + * A method that allows you to get a view based on the give selector type + */ + IChimpView getView(ChimpManager manager); +} diff --git a/chimpchat/src/com/android/chimpchat/core/MultiSelectorText.java b/chimpchat/src/com/android/chimpchat/core/MultiSelectorText.java new file mode 100644 index 0000000..c7bf362 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/MultiSelectorText.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import com.google.common.collect.Lists; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** A class for selecting objects by their text */ +public class MultiSelectorText implements IMultiSelector { + private static final Logger LOG = Logger.getLogger(ChimpView.class.getName()); + private String text; + + /** + * @param text the text which to select objects by + */ + public MultiSelectorText(String text) { + this.text = text; + } + + /** + * A method for selecting views by the given text. + * @return The collection of views that contain the given text + */ + public Collection getViews(ChimpManager manager) { + String response; + List ids; + try { + response = manager.getViewsWithText(text); + ids = Arrays.asList(response.split(" ")); + } catch (IOException e) { + LOG.log(Level.SEVERE, "Error communicating with device: " + e.getMessage()); + return new ArrayList(); + } + /* We make sure this has an even number of results because we don't necessarily know how + * many views with the given textthere are, but we know all of the views will return a pair + * of accessibility ids */ + if (ids.size() % 2 == 0) { + List views = new ArrayList(); + for (int i = 0; i < ids.size()/2; i++) { + List accessibilityIds = + Lists.newArrayList(ids.get(2 * i ), ids.get(2 * i + 1)); + ChimpView view = new ChimpView(ChimpView.ACCESSIBILITY_IDS, accessibilityIds); + view.setManager(manager); + views.add(view); + } + return views; + } + LOG.log(Level.SEVERE, "Error retrieving views: " + response); + return Collections.emptyList(); + } +} diff --git a/chimpchat/src/com/android/chimpchat/core/PhysicalButton.java b/chimpchat/src/com/android/chimpchat/core/PhysicalButton.java index 1da571e..8faabdd 100644 --- a/chimpchat/src/com/android/chimpchat/core/PhysicalButton.java +++ b/chimpchat/src/com/android/chimpchat/core/PhysicalButton.java @@ -16,10 +16,10 @@ package com.android.chimpchat.core; public enum PhysicalButton { - HOME("home"), - SEARCH("search"), - MENU("menu"), - BACK("back"), + HOME("KEYCODE_HOME"), + SEARCH("KEYCODE_SEARCH"), + MENU("KEYCODE_MENU"), + BACK("KEYCODE_BACK"), DPAD_UP("DPAD_UP"), DPAD_DOWN("DPAD_DOWN"), DPAD_LEFT("DPAD_LEFT"), diff --git a/chimpchat/src/com/android/chimpchat/core/SelectorAccessibilityIds.java b/chimpchat/src/com/android/chimpchat/core/SelectorAccessibilityIds.java new file mode 100644 index 0000000..7e534b3 --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/SelectorAccessibilityIds.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import com.google.common.collect.Lists; + +/* A class for selecting objects by their accessibility ids */ +public class SelectorAccessibilityIds implements ISelector { + private int windowId; + private int accessibilityId; + + /** + * @param windowId the window id of the node you want to select + * @param accessibilityId the accessibility id of the node you want to select + */ + public SelectorAccessibilityIds(int windowId, int accessibilityId) { + this.windowId = windowId; + this.accessibilityId = accessibilityId; + } + + /** + * A method for selecting a view by the given accessibility ids. + * @param manager The manager object used for interacting with the device. + * @return The view with the given accessibility ids. + */ + public IChimpView getView(ChimpManager manager) { + ChimpView view = new ChimpView(ChimpView.ACCESSIBILITY_IDS, + Lists.newArrayList(Integer.toString(windowId), Integer.toString(accessibilityId))); + view.setManager(manager); + return view; + } +} diff --git a/chimpchat/src/com/android/chimpchat/core/SelectorId.java b/chimpchat/src/com/android/chimpchat/core/SelectorId.java new file mode 100644 index 0000000..aa3598d --- /dev/null +++ b/chimpchat/src/com/android/chimpchat/core/SelectorId.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.chimpchat.core; + +import com.android.chimpchat.ChimpManager; + +import com.google.common.collect.Lists; + +/* A class for selecting objects by their id */ +public class SelectorId implements ISelector { + private String id; + /** + * @param id the id to select objects by + */ + public SelectorId(String id){ + this.id = id; + } + + /** + * A method for selecting a view by the given id. + * @return The view with the given id + */ + public IChimpView getView(ChimpManager manager) { + ChimpView view = new ChimpView(ChimpView.VIEW_ID, Lists.newArrayList(id)); + view.setManager(manager); + return view; + } +} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java index 61e92a0..e60d12e 100644 --- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java +++ b/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java @@ -20,6 +20,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Collections2; import com.android.chimpchat.ChimpChat; +import com.android.chimpchat.core.By; +import com.android.chimpchat.core.IChimpView; import com.android.chimpchat.core.IChimpDevice; import com.android.chimpchat.core.IChimpImage; import com.android.chimpchat.core.TouchPressType; @@ -31,11 +33,13 @@ import org.python.core.ArgParser; import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyDictionary; +import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyTuple; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -177,19 +181,14 @@ public class MonkeyDevice extends PyObject implements ClassDictInit { Preconditions.checkNotNull(ap); String name = ap.getString(0); - String touchType = ap.getString(1); + String touchType = ap.getString(1, DOWN_AND_UP); // The old docs had this string, and so in favor of maintaining // backwards compatibility, let's special case it to the new one. if (touchType.equals("DOWN_AND_UP")){ touchType = "downAndUp"; } - TouchPressType type = TouchPressType.fromIdentifier(ap.getString(1)); - if (type == null) { - LOG.warning(String.format("Invalid TouchPressType specified (%s) default used instead", - ap.getString(1))); - type = TouchPressType.DOWN_AND_UP; - } + TouchPressType type = TouchPressType.fromIdentifier(touchType); impl.press(name, type); } @@ -357,4 +356,74 @@ public class MonkeyDevice extends PyObject implements ClassDictInit { impl.wake(); } + + + @MonkeyRunnerExported(doc = "Retrieve the properties that can be queried") + public PyList getPropertyList(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + Collection properties = impl.getPropertyList(); + return new PyList(properties); + } + + @MonkeyRunnerExported(doc = "Retrieve the view ids for the current application") + public PyList getViewIdList(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + Collection viewIds = impl.getViewIdList(); + return new PyList(viewIds); + } + + //Because the pythonic way is to have flatter hierarchies, rather than doing the + //findView(By.id("foo")) style the java code uses, I'm going to expose them as individual + //method calls. This is similar to WebDriver's python bindings. + @MonkeyRunnerExported(doc = "Obtains the view with the specified id.", + args = {"id"}, + argDocs = {"The id of the view to retrieve."}, + returns = "The view object with the specified id.") + public MonkeyView getViewById(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + String id = ap.getString(0); + IChimpView view = impl.getView(By.id(id)); + return new MonkeyView(view); + } + + @MonkeyRunnerExported(doc = "Obtains the view with the specified accessibility ids.", + args = {"windowId", "accessibility id"}, + argDocs = {"The window id of the view to retrieve.", + "The accessibility id of the view to retrieve."}, + returns = "The view object with the specified id.") + public MonkeyView getViewByAccessibilityIds(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + int windowId = ap.getInt(0); + int accessibilityId = ap.getInt(1); + IChimpView view = impl.getView(By.accessibilityIds(windowId, accessibilityId)); + return new MonkeyView(view); + } + + @MonkeyRunnerExported(doc = "Obtains current root view", + returns = "The root view object") + public MonkeyView getRootView(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new MonkeyView(impl.getRootView()); + } + + @MonkeyRunnerExported(doc = "Obtains a list of views that contain the specified text.", + args = {"text"}, + argDocs = {"The text to search for"}, + returns = "A list of view objects that contain the specified text.") + public PyList getViewsByText(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + String text = ap.getString(0); + Collection views = impl.getViews(By.text(text)); + PyList pyViews = new PyList(); + for (IChimpView view : views) { + pyViews.append(new MonkeyView(view)); + } + return pyViews; + } } diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java new file mode 100644 index 0000000..98b2ecc --- /dev/null +++ b/monkeyrunner/src/com/android/monkeyrunner/MonkeyRect.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.monkeyrunner; + +import com.android.chimpchat.core.ChimpRect; + +import com.android.monkeyrunner.doc.MonkeyRunnerExported; + +import org.python.core.ArgParser; +import org.python.core.ClassDictInit; +import org.python.core.PyInteger; +import org.python.core.PyList; +import org.python.core.PyObject; + +import java.util.List; +import java.util.LinkedList; +import java.util.logging.Logger; + +/* + * A Jython wrap for the ChimpRect class that stores coordinate information for views + */ +@MonkeyRunnerExported(doc = "Represents the coordinates of a rectangular object") +public class MonkeyRect extends PyObject implements ClassDictInit { + private static final Logger LOG = Logger.getLogger(MonkeyRect.class.getName()); + + private ChimpRect rect; + + @MonkeyRunnerExported(doc = "The x coordinate of the left side of the rectangle") + public int left; + @MonkeyRunnerExported(doc = "The y coordinate of the top side of the rectangle") + public int top; + @MonkeyRunnerExported(doc = "The x coordinate of the right side of the rectangle") + public int right; + @MonkeyRunnerExported(doc = "The y coordinate of the bottom side of the rectangle") + public int bottom; + + public static void classDictInit(PyObject dict) { + JythonUtils.convertDocAnnotationsForClass(MonkeyRect.class, dict); + } + + public MonkeyRect(ChimpRect rect) { + this.rect = rect; + this.left = rect.left; + this.right = rect.right; + this.top = rect.top; + this.bottom = rect.bottom; + } + + @MonkeyRunnerExported(doc = "Returns the width of the rectangle", + returns = "The width of the rectangle as an integer") + public PyInteger getWidth() { + return new PyInteger(right-left); + } + + @MonkeyRunnerExported(doc = "Returns the height of the rectangle", + returns = "The height of the rectangle as an integer") + public PyInteger getHeight() { + return new PyInteger(bottom-top); + } + + @MonkeyRunnerExported(doc = "Returns a two item list that contains the x and y value of " + + "the center of the rectangle", + returns = "The center coordinates as a two item list of integers") + public PyList getCenter(){ + List center = new LinkedList(); + /* Center x coordinate */ + center.add(new PyInteger(left+(right-left)/2)); + /* Center y coordinate */ + center.add(new PyInteger(top+(bottom-top)/2)); + return new PyList(center); + } +} diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java new file mode 100644 index 0000000..8c1edb8 --- /dev/null +++ b/monkeyrunner/src/com/android/monkeyrunner/MonkeyView.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.monkeyrunner; + +import com.google.common.base.Preconditions; + +import com.android.chimpchat.core.IChimpView; + +import com.android.monkeyrunner.doc.MonkeyRunnerExported; + +import org.python.core.ArgParser; +import org.python.core.ClassDictInit; +import org.python.core.PyBoolean; +import org.python.core.PyInteger; +import org.python.core.PyList; +import org.python.core.PyObject; +import org.python.core.PyString; + +import java.util.List; +import java.util.logging.Logger; + +/* + * Jython wrapper for the ChimpView class + */ +@MonkeyRunnerExported(doc = "Represents a view object.") +public class MonkeyView extends PyObject implements ClassDictInit { + private static final Logger LOG = Logger.getLogger(MonkeyView.class.getName()); + + private IChimpView impl; + + public static void classDictInit(PyObject dict) { + JythonUtils.convertDocAnnotationsForClass(MonkeyView.class, dict); + } + + public MonkeyView(IChimpView impl) { + this.impl = impl; + } + + @MonkeyRunnerExported(doc = "Get the checked status of the view", + returns = "A boolean value for whether the item is checked or not") + public PyBoolean getChecked(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyBoolean(impl.getChecked()); + } + + @MonkeyRunnerExported(doc = "Returns the class name of the view", + returns = "The class name of the view as a string") + public PyString getViewClass(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyString(impl.getViewClass()); + } + + @MonkeyRunnerExported(doc = "Returns the text contained by the view", + returns = "The text contained in the view") + public PyString getText(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyString(impl.getText()); + } + + @MonkeyRunnerExported(doc = "Returns the location of the view in the form of a MonkeyRect", + returns = "The location of the view as a MonkeyRect object") + public MonkeyRect getLocation(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new MonkeyRect(impl.getLocation()); + } + + @MonkeyRunnerExported(doc = "Returns the enabled status of the view", + returns = "The enabled status of the view as a boolean") + public PyBoolean getEnabled(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyBoolean(impl.getEnabled()); + } + + @MonkeyRunnerExported(doc = "Returns the selected status of the view", + returns = "The selected status of the view as a boolean") + public PyBoolean getSelected(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyBoolean(impl.getSelected()); + } + + @MonkeyRunnerExported(doc = "Sets the selected status of the view", + args = {"selected"}, + argDocs = { "The boolean value to set selected to" }) + public void setSelected(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + + PyBoolean pySelected = (PyBoolean) ap.getPyObject(0, new PyBoolean(false)); + boolean selected = (Boolean) pySelected.__tojava__(Boolean.class); + impl.setSelected(selected); + } + + @MonkeyRunnerExported(doc = "Returns the focused status of the view", + returns = "The focused status of the view as a boolean") + public PyBoolean getFocused(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + return new PyBoolean(impl.getFocused()); + } + + @MonkeyRunnerExported(doc = "Sets the focused status of the view", + args = {"focused"}, + argDocs = { "The boolean value to set focused to" }) + public void setFocused(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + + PyBoolean pyFocused = (PyBoolean) ap.getPyObject(0, new PyBoolean(false)); + boolean focused = (Boolean) pyFocused.__tojava__(Boolean.class); + impl.setFocused(focused); + } + + @MonkeyRunnerExported(doc = "Returns the parent of the current view", + returns = "The parent of the view as a MonkeyView object") + public MonkeyView getParent(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + MonkeyView parent = new MonkeyView(impl.getParent()); + return parent; + } + + @MonkeyRunnerExported(doc = "Returns the children of the current view", + returns = "The children of the view as a list of MonkeyView objects") + public PyList getChildren(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + List chimpChildren = impl.getChildren(); + PyList children = new PyList(); + for (IChimpView child : chimpChildren) { + children.append(new MonkeyView(child)); + } + return children; + } + + @MonkeyRunnerExported(doc = "Returns the accessibility ids of the current view", + returns = "The accessibility ids of the view as a list of ints") + public PyList getAccessibilityIds(PyObject[] args, String[] kws) { + ArgParser ap = JythonUtils.createArgParser(args, kws); + Preconditions.checkNotNull(ap); + int[] ids = impl.getAccessibilityIds(); + PyList pyIds = new PyList(); + for (int i = 0; i < ids.length; i++) { + pyIds.append(new PyInteger(ids[i])); + } + return pyIds; + } + +} -- cgit v1.1