• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package com.android.monkeyrunner.recorder;
17 
18 import com.android.monkeyrunner.MonkeyDevice;
19 import com.android.chimpchat.core.IChimpImage;
20 import com.android.chimpchat.core.IChimpDevice;
21 import com.android.monkeyrunner.recorder.actions.Action;
22 import com.android.monkeyrunner.recorder.actions.DragAction;
23 import com.android.monkeyrunner.recorder.actions.DragAction.Direction;
24 import com.android.monkeyrunner.recorder.actions.PressAction;
25 import com.android.monkeyrunner.recorder.actions.TouchAction;
26 import com.android.monkeyrunner.recorder.actions.TypeAction;
27 import com.android.monkeyrunner.recorder.actions.WaitAction;
28 
29 import java.awt.BorderLayout;
30 import java.awt.Dimension;
31 import java.awt.Graphics2D;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.awt.event.MouseAdapter;
35 import java.awt.event.MouseEvent;
36 import java.awt.image.BufferedImage;
37 import java.io.FileNotFoundException;
38 import java.util.Map;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41 
42 import javax.swing.BoxLayout;
43 import javax.swing.ImageIcon;
44 import javax.swing.JButton;
45 import javax.swing.JComboBox;
46 import javax.swing.JFileChooser;
47 import javax.swing.JFrame;
48 import javax.swing.JLabel;
49 import javax.swing.JList;
50 import javax.swing.JOptionPane;
51 import javax.swing.JPanel;
52 import javax.swing.JScrollPane;
53 import javax.swing.JTextField;
54 import javax.swing.SwingUtilities;
55 import javax.swing.Timer;
56 
57 /**
58  * MainFrame for MonkeyRecorder.
59  */
60 public class MonkeyRecorderFrame extends JFrame {
61     private static final Logger LOG =
62         Logger.getLogger(MonkeyRecorderFrame.class.getName());
63 
64     private final IChimpDevice device;
65 
66     private static final long serialVersionUID = 1L;
67     private JPanel jContentPane = null;
68     private JLabel display = null;
69     private JScrollPane historyPanel = null;
70     private JPanel actionPanel = null;
71     private JButton waitButton = null;
72     private JButton pressButton = null;
73     private JButton typeButton = null;
74     private JButton flingButton = null;
75     private JButton exportActionButton = null;
76 
77     private JButton refreshButton = null;
78 
79     private BufferedImage currentImage;  //  @jve:decl-index=0:
80     private BufferedImage scaledImage = new BufferedImage(320, 480,
81             BufferedImage.TYPE_INT_ARGB);  //  @jve:decl-index=0:
82 
83     private JList historyList;
84     private ActionListModel actionListModel;
85 
86     private final Timer refreshTimer = new Timer(1000, new ActionListener() {
87         @Override
88         public void actionPerformed(ActionEvent e) {
89             refreshDisplay();  //  @jve:decl-index=0:
90         }
91     });
92 
93     /**
94      * This is the default constructor
95      */
MonkeyRecorderFrame(IChimpDevice device)96     public MonkeyRecorderFrame(IChimpDevice device) {
97         this.device = device;
98         initialize();
99     }
100 
initialize()101     private void initialize() {
102         this.setSize(400, 600);
103         this.setContentPane(getJContentPane());
104         this.setTitle("MonkeyRecorder");
105 
106         SwingUtilities.invokeLater(new Runnable() {
107             @Override
108             public void run() {
109                 refreshDisplay();
110             }});
111         refreshTimer.start();
112     }
113 
refreshDisplay()114     private void refreshDisplay() {
115         IChimpImage snapshot = device.takeSnapshot();
116         currentImage = snapshot.createBufferedImage();
117 
118         Graphics2D g = scaledImage.createGraphics();
119         g.drawImage(currentImage, 0, 0,
120                 scaledImage.getWidth(), scaledImage.getHeight(),
121                 null);
122         g.dispose();
123 
124         display.setIcon(new ImageIcon(scaledImage));
125 
126         pack();
127     }
128 
129     /**
130      * This method initializes jContentPane
131      *
132      * @return javax.swing.JPanel
133      */
getJContentPane()134     private JPanel getJContentPane() {
135         if (jContentPane == null) {
136             display = new JLabel();
137             jContentPane = new JPanel();
138             jContentPane.setLayout(new BorderLayout());
139             jContentPane.add(display, BorderLayout.CENTER);
140             jContentPane.add(getHistoryPanel(), BorderLayout.EAST);
141             jContentPane.add(getActionPanel(), BorderLayout.NORTH);
142 
143             display.setPreferredSize(new Dimension(320, 480));
144 
145             display.addMouseListener(new MouseAdapter() {
146                 @Override
147                 public void mouseClicked(MouseEvent event) {
148                     touch(event);
149                 }
150             });
151         }
152         return jContentPane;
153     }
154 
155     /**
156      * This method initializes historyPanel
157      *
158      * @return javax.swing.JScrollPane
159      */
getHistoryPanel()160     private JScrollPane getHistoryPanel() {
161         if (historyPanel == null) {
162             historyPanel = new JScrollPane();
163             historyPanel.getViewport().setView(getHistoryList());
164         }
165         return historyPanel;
166     }
167 
getHistoryList()168     private JList getHistoryList() {
169         if (historyList == null) {
170             actionListModel = new ActionListModel();
171             historyList = new JList(actionListModel);
172         }
173         return historyList;
174     }
175 
176     /**
177      * This method initializes actionPanel
178      *
179      * @return javax.swing.JPanel
180      */
getActionPanel()181     private JPanel getActionPanel() {
182         if (actionPanel == null) {
183             actionPanel = new JPanel();
184             actionPanel.setLayout(new BoxLayout(getActionPanel(), BoxLayout.X_AXIS));
185             actionPanel.add(getWaitButton(), null);
186             actionPanel.add(getPressButton(), null);
187             actionPanel.add(getTypeButton(), null);
188             actionPanel.add(getFlingButton(), null);
189             actionPanel.add(getExportActionButton(), null);
190             actionPanel.add(getRefreshButton(), null);
191         }
192         return actionPanel;
193     }
194 
195     /**
196      * This method initializes waitButton
197      *
198      * @return javax.swing.JButton
199      */
getWaitButton()200     private JButton getWaitButton() {
201         if (waitButton == null) {
202             waitButton = new JButton();
203             waitButton.setText("Wait");
204             waitButton.addActionListener(new java.awt.event.ActionListener() {
205                 @Override
206                 public void actionPerformed(java.awt.event.ActionEvent e) {
207                     String howLongStr = JOptionPane.showInputDialog("How many seconds to wait?");
208                     if (howLongStr != null) {
209                         float howLong = Float.parseFloat(howLongStr);
210                         addAction(new WaitAction(howLong));
211                     }
212                 }
213             });
214         }
215         return waitButton;
216     }
217 
218     /**
219      * This method initializes pressButton
220      *
221      * @return javax.swing.JButton
222      */
getPressButton()223     private JButton getPressButton() {
224         if (pressButton == null) {
225             pressButton = new JButton();
226             pressButton.setText("Press a Button");
227             pressButton.addActionListener(new java.awt.event.ActionListener() {
228                 @Override
229                 public void actionPerformed(java.awt.event.ActionEvent e) {
230                     JPanel panel = new JPanel();
231                     JLabel text = new JLabel("What button to press?");
232                     JComboBox keys = new JComboBox(PressAction.KEYS);
233                     keys.setEditable(true);
234                     JComboBox direction = new JComboBox(PressAction.DOWNUP_FLAG_MAP.values().toArray());
235                     panel.add(text);
236                     panel.add(keys);
237                     panel.add(direction);
238 
239                     int result = JOptionPane.showConfirmDialog(null, panel, "Input", JOptionPane.OK_CANCEL_OPTION);
240                     if (result == JOptionPane.OK_OPTION) {
241                         // Look up the "flag" value for the press choice
242                         Map<String, String> lookupMap = PressAction.DOWNUP_FLAG_MAP.inverse();
243                         String flag = lookupMap.get(direction.getSelectedItem());
244                         addAction(new PressAction((String) keys.getSelectedItem(), flag));
245                     }
246                 }
247             });
248         }
249         return pressButton;
250     }
251 
252     /**
253      * This method initializes typeButton
254      *
255      * @return javax.swing.JButton
256      */
getTypeButton()257     private JButton getTypeButton() {
258         if (typeButton == null) {
259             typeButton = new JButton();
260             typeButton.setText("Type Something");
261             typeButton.addActionListener(new java.awt.event.ActionListener() {
262                 @Override
263                 public void actionPerformed(java.awt.event.ActionEvent e) {
264                     String whatToType = JOptionPane.showInputDialog("What to type?");
265                     if (whatToType != null) {
266                         addAction(new TypeAction(whatToType));
267                     }
268                 }
269             });
270         }
271         return typeButton;
272     }
273 
274     /**
275      * This method initializes flingButton
276      *
277      * @return javax.swing.JButton
278      */
getFlingButton()279     private JButton getFlingButton() {
280         if (flingButton == null) {
281             flingButton = new JButton();
282             flingButton.setText("Fling");
283             flingButton.addActionListener(new java.awt.event.ActionListener() {
284                 @Override
285                 public void actionPerformed(java.awt.event.ActionEvent e) {
286                     JPanel panel = new JPanel();
287                     panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
288                     panel.add(new JLabel("Which Direction to fling?"));
289                     JComboBox directionChooser = new JComboBox(DragAction.Direction.getNames());
290                     panel.add(directionChooser);
291                     panel.add(new JLabel("How long to drag (in ms)?"));
292                     JTextField ms = new JTextField();
293                     ms.setText("1000");
294                     panel.add(ms);
295                     panel.add(new JLabel("How many steps to do it in?"));
296                     JTextField steps = new JTextField();
297                     steps.setText("10");
298                     panel.add(steps);
299 
300 
301 
302                     int result = JOptionPane.showConfirmDialog(null, panel, "Input", JOptionPane.OK_CANCEL_OPTION);
303                     if (result == JOptionPane.OK_OPTION) {
304                         DragAction.Direction dir =
305                             DragAction.Direction.valueOf((String) directionChooser.getSelectedItem());
306                         long millis = Long.parseLong(ms.getText());
307                         int numSteps = Integer.parseInt(steps.getText());
308 
309                         addAction(newFlingAction(dir, numSteps, millis));
310                     }
311                 }
312             });
313         }
314         return flingButton;
315     }
316 
newFlingAction(Direction dir, int numSteps, long millis)317     private DragAction newFlingAction(Direction dir, int numSteps, long millis) {
318         int width = Integer.parseInt(device.getProperty("display.width"));
319         int height = Integer.parseInt(device.getProperty("display.height"));
320 
321         // Adjust the w/h to a pct of the total size, so we don't hit things on the "outside"
322         width = (int) (width * 0.8f);
323         height = (int) (height * 0.8f);
324         int minW = (int) (width * 0.2f);
325         int minH = (int) (height * 0.2f);
326 
327         int midWidth = width / 2;
328         int midHeight = height / 2;
329 
330         int startx = minW;
331         int starty = minH;
332         int endx = minW;
333         int endy = minH;
334 
335         switch (dir) {
336             case NORTH:
337                 startx = endx = midWidth;
338                 starty = height;
339                 break;
340             case SOUTH:
341                 startx = endx = midWidth;
342                 endy = height;
343                 break;
344             case EAST:
345                 starty = endy = midHeight;
346                 endx = width;
347                 break;
348             case WEST:
349                 starty = endy = midHeight;
350                 startx = width;
351                 break;
352         }
353 
354         return new DragAction(dir, startx, starty, endx, endy, numSteps, millis);
355     }
356 
357     /**
358      * This method initializes exportActionButton
359      *
360      * @return javax.swing.JButton
361      */
getExportActionButton()362     private JButton getExportActionButton() {
363         if (exportActionButton == null) {
364             exportActionButton = new JButton();
365             exportActionButton.setText("Export Actions");
366             exportActionButton.addActionListener(new java.awt.event.ActionListener() {
367                 @Override
368                 public void actionPerformed(java.awt.event.ActionEvent ev) {
369                     JFileChooser fc = new JFileChooser();
370                     if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
371                         try {
372                             actionListModel.export(fc.getSelectedFile());
373                         } catch (FileNotFoundException e) {
374                             LOG.log(Level.SEVERE, "Unable to save file", e);
375                         }
376                     }
377                 }
378             });
379         }
380         return exportActionButton;
381     }
382 
383     /**
384      * This method initializes refreshButton
385      *
386      * @return javax.swing.JButton
387      */
getRefreshButton()388     private JButton getRefreshButton() {
389         if (refreshButton == null) {
390             refreshButton = new JButton();
391             refreshButton.setText("Refresh Display");
392             refreshButton.addActionListener(new java.awt.event.ActionListener() {
393                 @Override
394                 public void actionPerformed(java.awt.event.ActionEvent e) {
395                     refreshDisplay();
396                 }
397             });
398         }
399         return refreshButton;
400     }
401 
touch(MouseEvent event)402     private void touch(MouseEvent event) {
403         int x = event.getX();
404         int y = event.getY();
405 
406         // Since we scaled the image down, our x/y are scaled as well.
407         double scalex = ((double) currentImage.getWidth()) / ((double) scaledImage.getWidth());
408         double scaley = ((double) currentImage.getHeight()) / ((double) scaledImage.getHeight());
409 
410         x = (int) (x * scalex);
411         y = (int) (y * scaley);
412 
413         switch (event.getID()) {
414             case MouseEvent.MOUSE_CLICKED:
415                 addAction(new TouchAction(x, y, MonkeyDevice.DOWN_AND_UP));
416                 break;
417             case MouseEvent.MOUSE_PRESSED:
418                 addAction(new TouchAction(x, y, MonkeyDevice.DOWN));
419                 break;
420             case MouseEvent.MOUSE_RELEASED:
421                 addAction(new TouchAction(x, y, MonkeyDevice.UP));
422                 break;
423         }
424     }
425 
addAction(Action a)426     public void addAction(Action a) {
427         actionListModel.add(a);
428         try {
429             a.execute(device);
430         } catch (Exception e) {
431             LOG.log(Level.SEVERE, "Unable to execute action!", e);
432         }
433     }
434 }
435