1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.monkeyrunner;
17
18import com.google.common.base.Functions;
19import com.google.common.base.Preconditions;
20import com.google.common.collect.Collections2;
21
22import com.android.chimpchat.ChimpChat;
23import com.android.chimpchat.core.IChimpBackend;
24import com.android.chimpchat.core.IChimpDevice;
25import com.android.chimpchat.core.IChimpImage;
26import com.android.chimpchat.core.ChimpImageBase;
27import com.android.monkeyrunner.doc.MonkeyRunnerExported;
28
29import org.python.core.ArgParser;
30import org.python.core.ClassDictInit;
31import org.python.core.PyException;
32import org.python.core.PyObject;
33
34import java.util.Collection;
35import java.util.logging.Level;
36import java.util.logging.Logger;
37
38import javax.swing.JOptionPane;
39
40/**
41 * This is the main interface class into the jython bindings.
42 */
43@MonkeyRunnerExported(doc = "Main entry point for MonkeyRunner")
44public class MonkeyRunner extends PyObject implements ClassDictInit {
45    private static final Logger LOG = Logger.getLogger(MonkeyRunner.class.getCanonicalName());
46    private static ChimpChat chimpchat;
47
48    public static void classDictInit(PyObject dict) {
49        JythonUtils.convertDocAnnotationsForClass(MonkeyRunner.class, dict);
50    }
51
52    static void setChimpChat(ChimpChat chimp){
53        chimpchat = chimp;
54    }
55
56
57    @MonkeyRunnerExported(doc = "Waits for the workstation to connect to the device.",
58            args = {"timeout", "deviceId"},
59            argDocs = {"The timeout in seconds to wait. The default is to wait indefinitely.",
60            "A regular expression that specifies the device name. See the documentation " +
61            "for 'adb' in the Developer Guide to learn more about device names."},
62            returns = "A ChimpDevice object representing the connected device.")
63    public static MonkeyDevice waitForConnection(PyObject[] args, String[] kws) {
64        ArgParser ap = JythonUtils.createArgParser(args, kws);
65        Preconditions.checkNotNull(ap);
66
67        long timeoutMs;
68        try {
69            double timeoutInSecs = JythonUtils.getFloat(ap, 0);
70            timeoutMs = (long) (timeoutInSecs * 1000.0);
71        } catch (PyException e) {
72            timeoutMs = Long.MAX_VALUE;
73        }
74
75        IChimpDevice device = chimpchat.waitForConnection(timeoutMs,
76                ap.getString(1, ".*"));
77        MonkeyDevice chimpDevice = new MonkeyDevice(device);
78        return chimpDevice;
79    }
80
81    @MonkeyRunnerExported(doc = "Pause the currently running program for the specified " +
82            "number of seconds.",
83            args = {"seconds"},
84            argDocs = {"The number of seconds to pause."})
85    public static void sleep(PyObject[] args, String[] kws) {
86        ArgParser ap = JythonUtils.createArgParser(args, kws);
87        Preconditions.checkNotNull(ap);
88
89        double seconds = JythonUtils.getFloat(ap, 0);
90
91        long ms = (long) (seconds * 1000.0);
92
93        try {
94            Thread.sleep(ms);
95        } catch (InterruptedException e) {
96            LOG.log(Level.SEVERE, "Error sleeping", e);
97        }
98    }
99
100    @MonkeyRunnerExported(doc = "Format and display the API reference for MonkeyRunner.",
101            args = { "format" },
102            argDocs = {"The desired format for the output, either 'text' for plain text or " +
103            "'html' for HTML markup."},
104            returns = "A string containing the help text in the desired format.")
105    public static String help(PyObject[] args, String[] kws) {
106        ArgParser ap = JythonUtils.createArgParser(args, kws);
107        Preconditions.checkNotNull(ap);
108
109        String format = ap.getString(0, "text");
110
111        return MonkeyRunnerHelp.helpString(format);
112    }
113
114    @MonkeyRunnerExported(doc = "Display an alert dialog to the process running the current " +
115            "script.  The dialog is modal, so the script stops until the user dismisses the " +
116            "dialog.",
117            args = { "message", "title", "okTitle" },
118            argDocs = {
119            "The message to display in the dialog.",
120            "The dialog's title. The default value is 'Alert'.",
121            "The text to use in the dialog button. The default value is 'OK'."
122    })
123    public static void alert(PyObject[] args, String[] kws) {
124        ArgParser ap = JythonUtils.createArgParser(args, kws);
125        Preconditions.checkNotNull(ap);
126
127        String message = ap.getString(0);
128        String title = ap.getString(1, "Alert");
129        String buttonTitle = ap.getString(2, "OK");
130
131        alert(message, title, buttonTitle);
132    }
133
134    @MonkeyRunnerExported(doc = "Display a dialog that accepts input. The dialog is ," +
135            "modal, so the script stops until the user clicks one of the two dialog buttons. To " +
136            "enter a value, the user enters the value and clicks the 'OK' button. To quit the " +
137            "dialog without entering a value, the user clicks the 'Cancel' button. Use the " +
138            "supplied arguments for this method to customize the text for these buttons.",
139            args = {"message", "initialValue", "title", "okTitle", "cancelTitle"},
140            argDocs = {
141            "The prompt message to display in the dialog.",
142            "The initial value to supply to the user. The default is an empty string)",
143            "The dialog's title. The default is 'Input'",
144            "The text to use in the dialog's confirmation button. The default is 'OK'." +
145            "The text to use in the dialog's 'cancel' button. The default is 'Cancel'."
146    },
147    returns = "The test entered by the user, or None if the user canceled the input;"
148    )
149    public static String input(PyObject[] args, String[] kws) {
150        ArgParser ap = JythonUtils.createArgParser(args, kws);
151        Preconditions.checkNotNull(ap);
152
153        String message = ap.getString(0);
154        String initialValue = ap.getString(1, "");
155        String title = ap.getString(2, "Input");
156
157        return input(message, initialValue, title);
158    }
159
160    @MonkeyRunnerExported(doc = "Display a choice dialog that allows the user to select a single " +
161            "item from a list of items.",
162            args = {"message", "choices", "title"},
163            argDocs = {
164            "The prompt message to display in the dialog.",
165            "An iterable Python type containing a list of choices to display",
166            "The dialog's title. The default is 'Input'" },
167            returns = "The 0-based numeric offset of the selected item in the iterable.")
168    public static int choice(PyObject[] args, String kws[]) {
169        ArgParser ap = JythonUtils.createArgParser(args, kws);
170        Preconditions.checkNotNull(ap);
171
172        String message = ap.getString(0);
173        Collection<String> choices = Collections2.transform(JythonUtils.getList(ap, 1),
174                Functions.toStringFunction());
175        String title = ap.getString(2, "Input");
176
177        return choice(message, title, choices);
178    }
179
180    @MonkeyRunnerExported(doc = "Loads a MonkeyImage from a file.",
181            args = { "path" },
182            argDocs = {
183            "The path to the file to load.  This file path is in terms of the computer running " +
184            "MonkeyRunner and not a path on the Android Device. " },
185            returns = "A new MonkeyImage representing the specified file")
186    public static MonkeyImage loadImageFromFile(PyObject[] args, String kws[]) {
187        ArgParser ap = JythonUtils.createArgParser(args, kws);
188        Preconditions.checkNotNull(ap);
189
190        String path = ap.getString(0);
191        IChimpImage image = ChimpImageBase.loadImageFromFile(path);
192        return new MonkeyImage(image);
193    }
194
195    /**
196     * Display an alert dialog.
197     *
198     * @param message the message to show.
199     * @param title the title of the dialog box.
200     * @param okTitle the title of the button.
201     */
202    public static void alert(String message, String title, String okTitle) {
203        Object[] options = { okTitle };
204        JOptionPane.showOptionDialog(null, message, title, JOptionPane.DEFAULT_OPTION,
205                JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
206    }
207
208    /**
209     * Display a dialog allow the user to pick a choice from a list of choices.
210     *
211     * @param message the message to show.
212     * @param title the title of the dialog box.
213     * @param choices the list of the choices to display.
214     * @return the index of the selected choice, or -1 if nothing was chosen.
215     */
216    public static int choice(String message, String title, Collection<String> choices) {
217        Object[] possibleValues = choices.toArray();
218        Object selectedValue = JOptionPane.showInputDialog(null, message, title,
219                JOptionPane.QUESTION_MESSAGE, null, possibleValues, possibleValues[0]);
220
221        for (int x = 0; x < possibleValues.length; x++) {
222            if (possibleValues[x].equals(selectedValue)) {
223                return x;
224            }
225        }
226        // Error
227        return -1;
228    }
229
230    /**
231     * Display a dialog that allows the user to input a text string.
232     *
233     * @param message the message to show.
234     * @param initialValue the initial value to display in the dialog
235     * @param title the title of the dialog box.
236     * @return the entered string, or null if cancelled
237     */
238    public static String input(String message, String initialValue, String title) {
239        return (String) JOptionPane.showInputDialog(null, message, title,
240                JOptionPane.QUESTION_MESSAGE, null, null, initialValue);
241    }
242}
243