/**
** Copyright (C) SAS Institute, All rights reserved.
** General Public License: http://www.opensource.org/licenses/gpl-license.php
**/
package com.jayway.android.robotium.remotecontrol.solo;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InvalidObjectException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.concurrent.TimeoutException;
import javax.swing.*;
import org.safs.sockets.RemoteException;
import org.safs.sockets.ShutdownInvocationException;
import org.safs.sockets.SocketProtocolListener;
/**
* Crude Test app for initial manual testing of Robotium Remote Control.
* <p>
* This is not recommended for first-time users to verify a new installation.
* Use the Setup instructions provided in the Release Notes for first-time use verification.
* <p>
* This app provides a minimalist crude UI for manually entering and sending messages using SoloRemoteControl
* implementing a SocketProtocol to communicate and control Android automation on a remote device or emulator.
* <p>
* Note this has been tested on both a real device and the Emulator. To use the Emulator you
* must have a working Emulator and AVD.
* <p>
* SampleCommand used to launch the emulator with an appropriate AVD:
* <p>
* emulator -no-snapstorage -avd SprintEvo
* <p>
* Steps to test the remote control concept:
* <ol>
* <p>
* <li>Insure the Android SAFS TCP Messenger APK has been built and installed
* on the device or emulator:
* <p>
* ant debug<br>
* adb install -r bin\SAFSTCPMessenger-debug.apk
* <p>
* <li>Insure the Robotium Test Runner AndroidManifest.xml has the correct android:targetPackage setting
* for the application to be tested--whatever that is:<br><pre>
* <instrumentation android:name="com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner"
* android:targetPackage="com.android.example.spinner"
* android:label="General-Purpose Robotium Test Runner"/>
* </pre>
* <p>
* <li>Insure the RobotiumTestRunner APK has been built and installed on the device or emulator:
* <p>
* ant debug<br>
* adb install -r bin\RobotiumTestRunner-debug.apk
* <p>
* <li>Insure the application to be tested (AUT) has been (re-)signed with the same certificates used
* to build the TestRunner and the TCPMessenger.
* <p>
* <li>Insure the AUT has been installed on the device or emulator.
* <p>
* <li>For the emulator, insure port forwarding has been activated:<br>
* <p>adb forward tcp:2411 tcp:2410<br>
* <p>
* <li>In a separate CMD window, monitor "adb logcat"
* <p>
* <li>In a separate CMD window, launch the Robotium Test Runner:
* <p>
* adb shell am instrument -w com.jayway.android.robotium.remotecontrol.client/com.jayway.android.robotium.remotecontrol.client.RobotiumTestRunner
* <p>
* You should see a SAFS TCP Messenger notification appear in the notification area on the device\emulator and
* there should be logcat messages showing the status of the Robotium Test Runner registering with the SAFS
* TCP Messenger.
* <p>
* <li>Insure your CLASSPATH contains references to the necessary JAR files, or include them on your
* command-line Java invocation:
* <p><ul>
* robotium-remotecontrol.jar<br/>
* safsautoandroid.jar<br/>
* safssockets.jar<br/>
* </ul>
* <p>
* <li>In a separate CMD window, launch the RemoteControlUI:
* <p>
* java com.jayway.android.robotium.remotecontrol.solo.RemoteControlUI
* <p>
* <li>Press the "Connect" button to attempt to establish remote control connection with the SAFS
* TCP Messenger on the device/emulator. Monitor the logcat to see the status of this. If everything worked the RemoteControlUI
* status line should read "REMOTE READY".
* <p>
* <li>Type "launch" and press "Send". The target app launcher Activity should get launched.
* <p>
* <li>Type "close" and press "Send". The target app should shutdown.
* <p>
* <li>Press the "Dispatch" button to perform a roundtrip dispatch of a Properties object.<br>
* The adb logcat window should show the properties received remotely on the Test Runner and the
* RemoteControlUI should then show a Dialog of the same properties PLUS remoteresultcode and
* remoteresultinfo properties returned back from the Test Runner.
* <p><li>Press the "Shutdown" button and the remote Robotium Test Runner and SAFS TCP Messenger
* should both shutdown and the Notification icon on the device/emulator should disappear.
* <p><li>RemoteControlUI will not be able to connect again until you relaunch the Instrumentation test again and
* the appropriate Notification is present on the emulator or device.
* </ol>
* @author Carl Nagle, SAS Institute, Inc.
* @see SoloRemoteControl
*/
public class RemoteControlUI extends JFrame implements SocketProtocolListener, ActionListener {
SoloRemoteControl server = null;
JPanel controls = null;
JLabel cmdLabel = null;
JTextField cmdField = null;
String sendAction = "send";
String connectAction = "connect";
String shutdownAction = "shutdown_hook";
String dispatchPropsAction = "dispatchprops";
JButton sendButton = null;
JButton connectButton = null;
JButton shutdownButton = null;
JButton dispatchPropsButton = null;
JTextField status = null;
Properties props = new Properties();
public RemoteControlUI() throws HeadlessException {
super();
createUI();
}
public RemoteControlUI(String title) throws HeadlessException {
super(title);
createUI();
}
Properties fillProperties(){
props.clear();
props.setProperty("action", "launchapplication");
props.setProperty("windowid", "windowObject");
props.setProperty("componentid", "childObject");
props.setProperty("param1", "any parameter");
props.setProperty("recordtype", "t");
return props;
}
void createUI(){
setTitle(getListenerName());
setName(getListenerName());
getAccessibleContext().setAccessibleName(getListenerName());
controls = new JPanel();
cmdLabel = new JLabel("Command:");
cmdField = new JTextField();
cmdField.setEditable(false);
cmdField.setEnabled(false);
cmdField.setMinimumSize(new Dimension(350,18));
cmdField.setPreferredSize(cmdField.getMinimumSize());
sendButton = new JButton("Send");
sendButton.setActionCommand(sendAction);
sendButton.addActionListener(this);
sendButton.setEnabled(false);
connectButton = new JButton("Connect");
connectButton.setActionCommand(connectAction);
connectButton.addActionListener(this);
connectButton.setEnabled(true);
shutdownButton = new JButton("Shutdown");
shutdownButton.setActionCommand(shutdownAction);
shutdownButton.addActionListener(this);
shutdownButton.setEnabled(false);
dispatchPropsButton = new JButton("Dispatch");
dispatchPropsButton.setActionCommand(dispatchPropsAction);
dispatchPropsButton.addActionListener(this);
dispatchPropsButton.setEnabled(false);
controls.add(cmdLabel);
controls.add(cmdField);
controls.add(sendButton);
controls.add(dispatchPropsButton);
controls.add(shutdownButton);
controls.add(connectButton);
getContentPane().add(controls, "North");
status = new JTextField();
status.setEditable(false);
getContentPane().add(status, "South");
pack();
int y = getHeight();
//setSize(320 + 250,y);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
setFocusableWindowState(true);
}
void onConnectAction(){
disableInteraction();
status.setText("Attempting Remote Server Connection...");
server = new SoloRemoteControl();
server.addListener(this);
server.start();
}
void onSendAction(){
disableInteraction();
status.setText("Attempting sendMessage: "+ cmdField.getText());
try{
server.performRemoteMessageCommand(cmdField.getText(), 3, 3);
}
catch(IllegalThreadStateException x){
}
catch(RemoteException x){
}
catch(TimeoutException x){
}
catch(ShutdownInvocationException x){
}
}
void onDispatchPropsAction(){
try{
server.performRemotePropsCommand(fillProperties(), 3, 3, 5);
}
catch(IllegalThreadStateException x){
}
catch(RemoteException x){
// TODO:
}
catch(TimeoutException x){
// TODO:
}
catch(ShutdownInvocationException x){
// TODO:
}
}
void onShutdownAction() {
disableInteraction();
status.setText("Attempting Remote Client Shutdown...");
try{
server.performRemoteShutdown(3,3,5);
}
catch(IllegalThreadStateException x){
}
catch(RemoteException x){
}
catch(TimeoutException x){
}
catch(ShutdownInvocationException x){
}
shutdownRemoteControl();
}
protected void disableInteraction(){
cmdField.setEnabled(false);
cmdField.setEditable(false);
sendButton.setEnabled(false);
shutdownButton.setEnabled(false);
dispatchPropsButton.setEnabled(false);
connectButton.setEnabled(false);
}
protected void enableInteraction(){
cmdField.setEnabled(true);
cmdField.setEditable(true);
sendButton.setEnabled(true);
shutdownButton.setEnabled(true);
dispatchPropsButton.setEnabled(true);
}
public String getListenerName() {
return getClass().getSimpleName();
}
public void onReceiveConnection() {
status.setText("REMOTE CONNECTED");
}
public void onReceiveDebug(String message) {
status.setText("REMOTE DEBUG: "+ message);
System.out.println(message);
}
public void onReceiveReady() {
status.setText("REMOTE READY");
enableInteraction();
connectButton.setEnabled(false);
}
public void onReceiveRunning() {
status.setText("REMOTE RUNNING");
connectButton.setEnabled(false);
disableInteraction();
}
public void onReceiveResult(int rc, String info) {
status.setText("REMOTE RESULT: "+ rc +" : "+ info);
}
public void onReceiveResultProperties(Properties result) {
String alertmsg = "Received Properties:\n\n";
Enumeration keys = result.keys();
String key;
while(keys.hasMoreElements()){
key = (String)keys.nextElement();
alertmsg += key +" = "+ result.getProperty(key)+"\n";
}
JOptionPane.showMessageDialog(this, alertmsg);
}
public void onReceiveMessage(String message) {
status.setText("REMOTE MESSAGE: "+ message);
}
public void actionPerformed(ActionEvent e) {
// there is only one action: send
if(e.getActionCommand().equals(connectAction)) {
onConnectAction();
}else if(e.getActionCommand().equals(sendAction)) {
onSendAction();
}else if(e.getActionCommand().equals(shutdownAction)) {
onShutdownAction();
}else if(e.getActionCommand().equals(dispatchPropsAction)) {
onDispatchPropsAction();
}
}
/**
* java org.safs.android.RemoteControlUI
*
* @param args -- none
*/
public static void main(String[] args) {
new RemoteControlUI("Test SocketServer");
}
protected void shutdownRemoteControl(){
disableInteraction();
connectButton.setEnabled(true);
try{server.shutdown();}catch(Exception x){}
try{server.removeListener(this);}catch(Exception x){}
server = null;
}
public void onReceiveLocalShutdown(int cause) {
status.setText("LocalShutdown: "+ cause);
shutdownRemoteControl();
}
public void onReceiveRemoteShutdown(int cause) {
status.setText("RemoteShutdown: "+ cause);
shutdownRemoteControl();
}
public void onReceiveException(String message) {
status.setText("REMOTE EXCEPTION: "+ message);
}
}