├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── README.md
├── default.properties
├── gen
└── org
│ └── example
│ └── touch
│ └── R.java
├── proguard.cfg
├── project.properties
├── res
├── drawable-hdpi
│ └── icon.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ └── icon.png
├── layout
│ ├── control.xml
│ └── main.xml
└── values
│ └── strings.xml
└── src
└── org
└── tayloredapps
└── remoteclient
├── AppDelegate.java
├── ClientListener.java
├── ClientThread.java
├── Controller.java
└── Touch.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/*
2 | .settings/*
3 | gen/*
4 | .classpath
5 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Touch
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Remote Desktop Controller v1.5
2 |
3 | Copyright 2010 Justin Taylor
4 | This software can be distributed under the terms of the
5 | GNU General Public License.
6 |
7 | This project was created for Android devices running 2.1 and higher.
8 |
9 | The Remote Desktop controller can control the mouse and keyboard of a dekstop
10 | computer from an Android device. There are two pieces of software needed for
11 | this to run properly. The DesktopRemoteServer which runs on the users desktop
12 | machine, and the Touchapp which runs on the user's Android device
13 |
14 | ## Deliverables
15 | What's that? You just want to use the app!?! You don't want to mess with the
16 | hassle of eclipse? In that case just download
17 | http://central.tayloredapps.org/server.jar and run it on any desktop that has
18 | JRE installed. Then mosy on over and download
19 | http://central.tayloredapps.org/Android-remote-client.apk to your android
20 | device.
21 |
22 | ## Remote Desktop Server
23 | https://github.com/justin-taylor/Remote-Desktop-Server
24 | This project must be imported into the eclipse workspace for the android
25 | application to be ran.
26 |
27 | ## Android Remote Client
28 | The Android app that send messages over wifi to the receiving server. The app is
29 | divided into three classes.
30 |
31 | 2. Touch
32 | This view allows the user to adjust the settings of he app. The
33 | first setting is the port that the messages are sent over. This
34 | must match the port set from the server UI on the DekstopRemoteServer.
35 | There is also a setting to control mouse sensitivity.
36 |
37 | 2. Controller
38 | This view is shown after the settings in touch are accepted. Listners
39 | receive user interactions, such as taps, movement and keyboard
40 | interactions, and are then translated into messages to be sent over the
41 | UDP socket established in the AppDelegate (See section 2.C).
42 |
43 | 2. AppDelegate
44 | The AppDelegate bridges the gap between the Touch view (2.A) and the
45 | Controller view (2.B). The settings from the Touch view are used to
46 | create a UDP socket that will send messages from the Controller view
47 | to the receiveing DesktopRemoteServer (1). If there is a connection
48 | issue this class will close the Controller view and present the touch
49 | view displaying and message about the issue.
50 |
51 | ## Known Bugs
52 |
53 | * Key Board Support:
54 | Not all Keys on the Android Keyboard are supported.
55 | Not entirely sure why. Some keys return the same
56 | key code in the onKey method Controller.java
57 |
58 | * Sever Connection Test:
59 | There should be a way to ensure server connectivity
60 | before switching to the Controller view. Currently
61 | a test message is sent to the server and listens for
62 | a message back (similar to a ping request), however
63 | the connection takes a couple of tries before connecting.
64 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # Project target.
2 | target=android-8
3 |
--------------------------------------------------------------------------------
/gen/org/example/touch/R.java:
--------------------------------------------------------------------------------
1 | /* AUTO-GENERATED FILE. DO NOT MODIFY.
2 | *
3 | * This class was automatically generated by the
4 | * aapt tool from the resource data it found. It
5 | * should not be modified by hand.
6 | */
7 |
8 | package org.example.touch;
9 |
10 | public final class R {
11 | public static final class attr {
12 | }
13 | public static final class drawable {
14 | public static final int icon=0x7f020000;
15 | }
16 | public static final class id {
17 | public static final int Button01=0x7f050015;
18 | public static final int Button02=0x7f050016;
19 | public static final int ButtonGroup=0x7f050002;
20 | public static final int EditText01=0x7f05000c;
21 | public static final int EditText02=0x7f05000e;
22 | public static final int EditText03=0x7f050013;
23 | public static final int KeyBoard=0x7f050005;
24 | public static final int LeftClickButton=0x7f050003;
25 | public static final int LinearLayout01=0x7f050006;
26 | public static final int RightClickButton=0x7f050004;
27 | public static final int ScreenCapture=0x7f050010;
28 | public static final int SeekBar01=0x7f05000a;
29 | public static final int TextView01=0x7f05000b;
30 | public static final int TextView02=0x7f05000d;
31 | public static final int TextView03=0x7f050009;
32 | public static final int TouchPad=0x7f050000;
33 | public static final int checkBox1=0x7f05000f;
34 | public static final int devicePort=0x7f050011;
35 | public static final int framerate=0x7f050012;
36 | public static final int keyboardbutton=0x7f050001;
37 | public static final int linearLayout1=0x7f050008;
38 | public static final int screenRatio=0x7f050014;
39 | public static final int scrollView1=0x7f050007;
40 | }
41 | public static final class layout {
42 | public static final int control=0x7f030000;
43 | public static final int main=0x7f030001;
44 | }
45 | public static final class string {
46 | public static final int app_name=0x7f040001;
47 | public static final int buttonHandler=0x7f040002;
48 | public static final int hello=0x7f040000;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class com.android.vending.licensing.ILicensingService
14 |
15 | -keepclasseswithmembernames class * {
16 | native ;
17 | }
18 |
19 | -keepclasseswithmembernames class * {
20 | public (android.content.Context, android.util.AttributeSet);
21 | }
22 |
23 | -keepclasseswithmembernames class * {
24 | public (android.content.Context, android.util.AttributeSet, int);
25 | }
26 |
27 | -keepclassmembers enum * {
28 | public static **[] values();
29 | public static ** valueOf(java.lang.String);
30 | }
31 |
32 | -keep class * implements android.os.Parcelable {
33 | public static final android.os.Parcelable$Creator *;
34 | }
35 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-14
12 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justin-taylor/Android-remote-client/85c6cc5c4e48c21a9da7bff512939fdc1862f015/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justin-taylor/Android-remote-client/85c6cc5c4e48c21a9da7bff512939fdc1862f015/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/justin-taylor/Android-remote-client/85c6cc5c4e48c21a9da7bff512939fdc1862f015/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/layout/control.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
26 |
27 |
28 |
34 |
35 |
40 |
41 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
20 |
21 |
28 |
29 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
52 |
53 |
59 |
60 |
66 |
67 |
76 |
77 |
78 |
79 |
88 |
89 |
90 |
95 |
96 |
97 |
106 |
107 |
108 |
109 |
118 |
119 |
120 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
141 |
142 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, Touch!
4 | Desktop Remote
5 | clickHandler
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/org/tayloredapps/remoteclient/AppDelegate.java:
--------------------------------------------------------------------------------
1 | // Copyright 2010 Justin Taylor
2 | // This software can be distributed under the terms of the
3 | // GNU General Public License.
4 |
5 | package org.tayloredapps.remoteclient;
6 |
7 | import android.app.Application;
8 | import android.content.Context;
9 | import android.net.ConnectivityManager;
10 |
11 | import org.tayloredapps.remoteclient.ClientThread;
12 |
13 | public class AppDelegate extends Application {
14 |
15 | private ClientThread client;
16 | private ClientListener listener;
17 | private Controller controller;
18 |
19 | public void onCreate(){
20 | super.onCreate();
21 | }
22 |
23 | public void setController(Controller c){
24 | controller = c;
25 | }
26 |
27 | public Controller getController()
28 | {
29 | return controller;
30 | }
31 |
32 |
33 |
34 | /***********************************************************************************
35 |
36 | Server Control
37 |
38 | ***********************************************************************************/
39 |
40 | public void createClientThread(String ipAddress, int port){
41 |
42 | client = new ClientThread(ipAddress, port);
43 |
44 | Thread cThread = new Thread(client);
45 | cThread.start();
46 | }
47 |
48 | public void createScreenCaptureThread(int listenerPort, int fps)
49 | {
50 | listener = new ClientListener(listenerPort, fps, this);
51 |
52 | Thread cThread = new Thread(listener);
53 | cThread.start();
54 | }
55 |
56 | public void sendMessage(String message){
57 | if(client != null)
58 | client.sendMessage(message);
59 | }
60 |
61 | public void stopServer(){
62 | if(client != null && client.connected){
63 | client.closeSocket();
64 | }
65 | client = null;
66 |
67 | if(listener != null)
68 | {
69 | listener.closeSocket();
70 | }
71 |
72 | listener = null;
73 | }
74 |
75 |
76 |
77 | /***********************************************************************************
78 |
79 | Testing Connectivity
80 |
81 | ***********************************************************************************/
82 |
83 | public boolean connected(){
84 |
85 | if(client != null)
86 | return client.connected;
87 |
88 | return false;
89 | }
90 |
91 | public boolean canAccessNetwork(){
92 | final ConnectivityManager connMgr = (ConnectivityManager)
93 | getSystemService(Context.CONNECTIVITY_SERVICE);
94 |
95 | android.net.NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
96 | if(wifi.isAvailable())
97 | return true;
98 |
99 | /*
100 | * For now the mobile connectivity does not matter
101 | * the scale of this project is local wireless networks
102 | *
103 | android.net.NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
104 | if(mobile.isAvailable())
105 | return true;
106 | */
107 |
108 | return false;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/org/tayloredapps/remoteclient/ClientListener.java:
--------------------------------------------------------------------------------
1 | package org.tayloredapps.remoteclient;
2 |
3 | import java.net.DatagramPacket;
4 | import java.net.DatagramSocket;
5 | import java.net.InetAddress;
6 | import java.net.NetworkInterface;
7 | import java.net.SocketException;
8 | import java.util.Enumeration;
9 | import java.util.Timer;
10 | import java.util.TimerTask;
11 |
12 | import messages.Constants;
13 |
14 | import android.graphics.Bitmap;
15 | import android.graphics.BitmapFactory;
16 | import android.util.Log;
17 |
18 | public class ClientListener implements Runnable{
19 |
20 | private InetAddress serverAddr;
21 | private int serverPort;
22 | private DatagramSocket socket;
23 | byte[] buf = new byte[65000];
24 | private DatagramPacket dgp;
25 | private AppDelegate delegate;
26 | private int framesPerSecond = -1;
27 | public boolean connected = false;
28 |
29 | public static int deviceWidth = 100;
30 | public static int deviceHeight = 100;
31 |
32 | public ClientListener(int port, int fps, AppDelegate del){
33 | delegate = del;
34 | framesPerSecond = fps;
35 |
36 | try{
37 |
38 | serverAddr = getLocalIpAddress();
39 | dgp = new DatagramPacket(buf, buf.length);
40 |
41 | }catch (Exception e){
42 | Log.e("ClientActivity", "C: Error", e);
43 | }
44 | serverPort = port;
45 | }
46 |
47 |
48 |
49 | public void run() {
50 | try {
51 | socket = new DatagramSocket(serverPort, serverAddr);
52 | connected = true;
53 |
54 | Timer timer = new Timer();
55 | int frames = 1000/framesPerSecond;
56 |
57 | timer.scheduleAtFixedRate(getImageTask, 0, frames);
58 |
59 | listen();
60 | }
61 | catch (Exception e) {
62 | Log.e("ClientActivity", "Client Connection Error", e);
63 | }
64 | }
65 |
66 |
67 |
68 | private TimerTask getImageTask = new TimerTask(){
69 |
70 | @Override
71 | public void run() {
72 | String message = new String(""+
73 | Constants.REQUESTIMAGE+
74 | Constants.DELIMITER+
75 | deviceWidth+
76 | Constants.DELIMITER+
77 | deviceHeight+"");
78 |
79 |
80 | delegate.sendMessage(message);
81 | }
82 | };
83 |
84 |
85 |
86 | private void listen()
87 | {
88 | while(connected){
89 |
90 | try{
91 | socket.receive(dgp);
92 | Bitmap bm = BitmapFactory.decodeByteArray(dgp.getData(), 0, 65000);
93 | Log.e("REQUESTINGSIZE", "SIZERECV: "+bm.getWidth()+" "+bm.getHeight());
94 | delegate.getController().setImage(bm);
95 | }catch(Exception e){
96 | e.printStackTrace();
97 | }
98 | }
99 | }
100 |
101 |
102 |
103 | public static InetAddress getLocalIpAddress() {
104 | try {
105 | for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
106 | NetworkInterface intf = en.nextElement();
107 | for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
108 | InetAddress inetAddress = enumIpAddr.nextElement();
109 | if (!inetAddress.isLoopbackAddress() && !inetAddress.toString().contains(":"))
110 | {
111 | return inetAddress;
112 | }
113 | }
114 | }
115 | } catch (SocketException ex) {
116 | Log.e("", ex.toString());
117 | }
118 | return null;
119 | }
120 |
121 |
122 |
123 | public void closeSocket(){
124 | if(socket != null) {
125 | socket.close();
126 | }
127 | connected = false;
128 | if(getImageTask != null) {
129 | getImageTask.cancel();
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/org/tayloredapps/remoteclient/ClientThread.java:
--------------------------------------------------------------------------------
1 | package org.tayloredapps.remoteclient;
2 |
3 | import java.net.DatagramPacket;
4 | import java.net.DatagramSocket;
5 | import java.net.InetAddress;
6 |
7 | import android.util.Log;
8 |
9 | //ClientThread Class implementation
10 | public class ClientThread implements Runnable {
11 |
12 | private InetAddress serverAddr;
13 | private int serverPort;
14 | private DatagramSocket socket;
15 | byte[] buf = new byte[65000];
16 |
17 | public boolean connected = false;
18 |
19 | public ClientThread(String ip, int port){
20 | try{
21 | serverAddr = InetAddress.getByName(ip);
22 | }
23 | catch (Exception e){
24 | Log.e("ClientActivity", "C: Error", e);
25 | }
26 | serverPort = port;
27 | }
28 |
29 | //Opens the socket and output buffer to the remote server
30 | public void run() {
31 | try {
32 | socket = new DatagramSocket();
33 | //socket.setSoTimeout(1000);
34 |
35 | connected = true;
36 |
37 | connected = testConnection();
38 | if(connected)
39 | surveyConnection();
40 | }
41 | catch (Exception e) {
42 | Log.e("ClientActivity", "Client Connection Error", e);
43 | }
44 | }
45 |
46 | public void sendMessage(String message){
47 | try {
48 | buf = message.getBytes();
49 | DatagramPacket out = new DatagramPacket(buf, buf.length, serverAddr, serverPort);
50 | socket.send(out);
51 | }
52 | catch (Exception e){
53 | closeSocketNoMessge();
54 | }
55 | }
56 |
57 | public void closeSocketNoMessge(){
58 | if(socket != null)
59 | {
60 | socket.close();
61 | }
62 | connected = false;
63 | }
64 |
65 | public void closeSocket(){
66 | sendMessage(new String("Close"));
67 |
68 | if(socket != null)
69 | {
70 | socket.close();
71 | }
72 |
73 | connected = false;
74 | }
75 |
76 | /*
77 | * Used to test connection with the server.
78 | */
79 |
80 | private boolean testConnection(){
81 | try {
82 | if(!connected)buf = new String("Connectivity").getBytes();
83 | else buf = new String("Connected").getBytes();
84 |
85 | DatagramPacket out = new DatagramPacket(buf, buf.length, serverAddr, serverPort);
86 | socket.send(out);
87 | }
88 | catch(Exception e){return false;}
89 |
90 | try{
91 | DatagramPacket in = new DatagramPacket(buf, buf.length);
92 | socket.receive(in);
93 | return true;
94 | }
95 | catch(Exception e){return false;}
96 | }
97 |
98 | private void surveyConnection(){
99 | int count = 0;
100 | while(connected){
101 | try{Thread.sleep(1000);}
102 | catch(Exception e){}
103 |
104 | if(!testConnection())
105 | count++;
106 | else
107 | count = 0;
108 |
109 | if(count == 3){
110 | closeSocket();
111 | return;
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/org/tayloredapps/remoteclient/Controller.java:
--------------------------------------------------------------------------------
1 | // Copyright 2010 Justin Taylor
2 | // This software can be distributed under the terms of the
3 | // GNU General Public License.
4 |
5 | package org.tayloredapps.remoteclient;
6 |
7 | import org.example.touch.R;
8 |
9 | import messages.Constants;
10 | import android.app.Activity;
11 | import android.os.Bundle;
12 | import android.os.Handler;
13 | import android.os.Looper;
14 | import android.util.DisplayMetrics;
15 | import android.util.Log;
16 |
17 | import android.view.View.OnTouchListener;
18 | import android.view.View.OnKeyListener;
19 | import android.view.*;
20 |
21 | import android.widget.Button;
22 | import android.widget.EditText;
23 | import android.widget.LinearLayout;
24 | import android.text.Editable;
25 | import android.text.TextWatcher;
26 |
27 | import android.view.inputmethod.InputMethodManager;
28 | import android.content.Context;
29 | import android.content.res.Configuration;
30 | import android.graphics.Bitmap;
31 | import android.graphics.drawable.BitmapDrawable;
32 |
33 | public class Controller extends Activity implements OnTouchListener, OnKeyListener{
34 |
35 | float lastXpos = 0;
36 | float lastYpos = 0;
37 |
38 | private int mouse_sensitivity = 1;
39 | private float screenRatio = 1.0f;
40 |
41 | boolean keyboard = false;
42 | Thread checking;
43 |
44 | Button Left;
45 | Button Right;
46 |
47 | int count = 0;
48 | int FRAME_RATE = 10;
49 |
50 | protected void onCreate(Bundle savedInstanceState) {
51 |
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.control);
54 |
55 | mouse_sensitivity = getIntent().getExtras().getInt("sensitivity");
56 | screenRatio = getIntent().getExtras().getFloat("ratio");
57 |
58 | // Set the width of the buttons to half the screen size
59 | Display display = getWindowManager().getDefaultDisplay();
60 | int width = display.getWidth();
61 |
62 | Left = (Button) findViewById(R.id.LeftClickButton);
63 | Right = (Button) findViewById(R.id.RightClickButton);
64 |
65 | Left.setWidth(width/2);
66 | Right.setWidth(width/2);
67 |
68 | Left.setOnTouchListener(this);
69 | Right.setOnTouchListener(this);
70 |
71 | ClientListener.deviceWidth = width;
72 | ClientListener.deviceHeight = display.getHeight() - Left.getHeight();
73 |
74 | View touchView = (View) findViewById(R.id.TouchPad);
75 | touchView.setOnTouchListener(this);
76 |
77 | EditText editText = (EditText) findViewById(R.id.KeyBoard);
78 | editText.setOnKeyListener(this);
79 | editText.addTextChangedListener(new TextWatcher(){
80 | public void afterTextChanged (Editable s){
81 | try{
82 | sendToAppDel(Constants.KEYBOARD + s.toString());
83 | } catch(IndexOutOfBoundsException e){}
84 | s.clear();
85 | }
86 |
87 | public void beforeTextChanged (CharSequence s, int start, int count, int after){}
88 | public void onTextChanged (CharSequence s, int start, int before, int count) {
89 | }
90 | });
91 |
92 | setImageRequestSizes();
93 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
94 | appDel.setController( this );
95 | }
96 |
97 | private void setImageRequestSizes() {
98 | DisplayMetrics metrics = new DisplayMetrics();
99 | WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
100 | Display display = wm.getDefaultDisplay();
101 | display.getMetrics(metrics);
102 | int width, height;
103 | width = metrics.widthPixels;
104 | height = metrics.heightPixels;
105 |
106 | ClientListener.deviceWidth = (int)(screenRatio * width);
107 | ClientListener.deviceHeight = (int)(screenRatio * height);
108 | Log.e("REQUESTINGSIZE", screenRatio+" "+ ClientListener.deviceWidth+" "+ClientListener.deviceHeight);
109 | }
110 |
111 | public void finish()
112 | {
113 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
114 | appDel.stopServer();
115 |
116 | super.finish();
117 | }
118 |
119 | public void onConfigurationChanged(Configuration newConfig) {
120 | setImageRequestSizes();
121 | super.onConfigurationChanged(newConfig);
122 | }
123 |
124 | public boolean onTouch(View v, MotionEvent event) {
125 | if(v == Left){
126 | switch ( event.getAction() ) {
127 | case MotionEvent.ACTION_DOWN: sendToAppDel(Constants.LEFTMOUSEDOWN); break;
128 | case MotionEvent.ACTION_UP: sendToAppDel(Constants.LEFTMOUSEUP); break;
129 | }
130 | }else if( v == Right){
131 | switch ( event.getAction() ) {
132 | case MotionEvent.ACTION_DOWN: sendToAppDel(Constants.RIGHTMOUSEDOWN); break;
133 | case MotionEvent.ACTION_UP: sendToAppDel(Constants.RIGHTMOUSEUP); break;
134 | }
135 | }
136 | else
137 | mousePadHandler(event);
138 |
139 | return true;
140 | }
141 |
142 | // detect keyboard event
143 | // and send to delegate
144 | //@Override
145 | public boolean onKey(View v, int c, KeyEvent event){
146 |
147 | // c is the event keycode
148 | if(event.getAction() == 1)
149 | {
150 | sendToAppDel( "" + Constants.KEYCODE+c);
151 | }
152 | // this will prevent the focus from moving off the text field
153 | if( c == KeyEvent.KEYCODE_DPAD_UP ||
154 | c == KeyEvent.KEYCODE_DPAD_DOWN ||
155 | c == KeyEvent.KEYCODE_DPAD_LEFT ||
156 | c == KeyEvent.KEYCODE_DPAD_RIGHT
157 | )
158 | return true;
159 |
160 | return false;
161 | }
162 |
163 | // Show and hide Keyboard by setting the
164 | // focus on a hidden text field
165 | public void keyClickHandler(View v){
166 | EditText editText = (EditText) findViewById(R.id.KeyBoard);
167 | InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
168 | if(keyboard){
169 | mgr.hideSoftInputFromWindow(editText.getWindowToken(), 0);
170 | keyboard = false;
171 | }
172 | else{
173 | mgr.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
174 | keyboard = true;
175 | }
176 | }
177 |
178 | // send message to AppDelegate class
179 | // to be sent to server on client desktop
180 | private void sendToAppDel(String message){
181 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
182 | if(appDel.connected()){
183 | appDel.sendMessage(message);
184 | }
185 | else{
186 | finish();
187 | }
188 | }
189 |
190 | private void sendToAppDel(char c){
191 | sendToAppDel(""+c);
192 | }
193 |
194 |
195 | public void setImage(final Bitmap bit){
196 | Handler handler = new Handler(Looper.getMainLooper());
197 | handler.post(new Runnable() {
198 |
199 | public void run() {
200 | LinearLayout layout = (LinearLayout) findViewById(R.id.TouchPad);
201 | BitmapDrawable drawable = new BitmapDrawable( bit );
202 | layout.setBackgroundDrawable( drawable );
203 | }
204 | });
205 |
206 |
207 | }
208 |
209 | // send a mouse message
210 | private void mousePadHandler(MotionEvent event) {
211 | int action = event.getAction();
212 | int touchCount = event.getPointerCount();
213 |
214 | // if a single touch
215 | if(touchCount == 1){
216 | switch(action){
217 |
218 | case 0: // touch down
219 | lastXpos = event.getX();
220 | lastYpos = event.getY();
221 | break;
222 |
223 | case 1: // touch up
224 | long deltaTime = event.getEventTime() - event.getDownTime();
225 | if(deltaTime < 250)
226 | sendToAppDel(Constants.LEFTCLICK);
227 | break;
228 |
229 | case 2: // moved
230 | float deltaX = (lastXpos - event.getX()) * -1;
231 | float deltaY = (lastYpos - event.getY()) * -1;
232 |
233 | sendToAppDel(Constants.createMoveMouseMessage(deltaX * mouse_sensitivity
234 | , deltaY * mouse_sensitivity));
235 |
236 | lastXpos = event.getX();
237 | lastYpos = event.getY();
238 | break;
239 |
240 | default: break;
241 | }
242 | }
243 |
244 | // if two touches send scroll message
245 | // based off MAC osx multi touch scrolls up and down
246 | else if(touchCount == 2){
247 | if(action == 2){
248 |
249 | float deltaY = event.getY() - lastYpos;
250 | float tolerance = 10;
251 |
252 | if (deltaY > tolerance){
253 | sendToAppDel(Constants.SCROLLUP);
254 | lastYpos = event.getY();
255 | }
256 | else if(deltaY < -1 * tolerance){
257 | sendToAppDel(Constants.SCROLLDOWN);
258 | lastYpos = event.getY();
259 | }
260 | }else lastYpos = event.getY();
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/src/org/tayloredapps/remoteclient/Touch.java:
--------------------------------------------------------------------------------
1 | // Copyright 2010 Justin Taylor
2 | // This software can be distributed under the terms of the
3 | // GNU General Public License.
4 |
5 | package org.tayloredapps.remoteclient;
6 |
7 | import org.example.touch.R;
8 |
9 | import android.app.Activity;
10 | import android.app.AlertDialog;
11 | import android.content.Intent;
12 | import android.os.Bundle;
13 | import android.view.View;
14 | import android.content.DialogInterface;
15 | import android.widget.Button;
16 | import android.widget.CheckBox;
17 | import android.widget.EditText;
18 | import android.widget.SeekBar;
19 | import android.content.SharedPreferences;
20 |
21 | public class Touch extends Activity{
22 |
23 | private EditText ipField;
24 | private EditText portField;
25 | private EditText listenerPortField;
26 | private SeekBar sensitivity;
27 | private CheckBox useScreenCap;
28 | private EditText frameRate;
29 | private EditText screenRatio;
30 |
31 | public static final String PREFS_NAME = "TouchSettings";
32 |
33 | public static final String IP_PREF = "ip_pref";
34 | public static final String PORT_PREF = "port_pref";
35 | public static final String SENSITIVITY_PREF = "sens_pref";
36 |
37 | public static final String LISTENER_PORT_PREF = "listener_pref";
38 | public static final String USE_SCREEN_CAP_PREF = "screen_pref";
39 | public static final String FRAME_RATE_PREF = "rate_pref";
40 | public static final String SCREEN_RATIO_PREF = "ratio_pref";
41 |
42 |
43 | /***********************************************************************************
44 |
45 | Activity Lifecycle
46 |
47 | ***********************************************************************************/
48 |
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 | setContentView(R.layout.main);
53 |
54 | ipField = (EditText) findViewById(R.id.EditText01);
55 | portField = (EditText) findViewById(R.id.EditText02);
56 | screenRatio = (EditText) findViewById(R.id.screenRatio);
57 | sensitivity = (SeekBar) findViewById(R.id.SeekBar01);
58 |
59 |
60 | listenerPortField = (EditText) findViewById(R.id.devicePort);
61 | useScreenCap = (CheckBox) findViewById(R.id.checkBox1);
62 | frameRate = (EditText) findViewById(R.id.framerate);
63 |
64 | // Set button listeners
65 | Button connectbutton = (Button) findViewById(R.id.Button01);
66 | connectbutton.setOnClickListener(new View.OnClickListener() {
67 | public void onClick(View v) {
68 | connectToServer();
69 |
70 | //Store used settings
71 | SharedPreferences prefs = getSharedPreferences(PREFS_NAME, 0);
72 | SharedPreferences.Editor editor = prefs.edit();
73 |
74 | editor.putInt(SENSITIVITY_PREF, sensitivity.getProgress());
75 | editor.putString(PORT_PREF, portField.getText().toString());
76 | editor.putString(IP_PREF, ipField.getText().toString());
77 | editor.putFloat(SCREEN_RATIO_PREF, Float.parseFloat(screenRatio.getText().toString()));
78 |
79 | editor.putString(LISTENER_PORT_PREF, listenerPortField.getText().toString());
80 | editor.putInt(FRAME_RATE_PREF, Integer.parseInt( frameRate.getText().toString()) );
81 | editor.putBoolean(USE_SCREEN_CAP_PREF, useScreenCap.isChecked());
82 |
83 | editor.commit();
84 |
85 | }
86 | });
87 |
88 | Button disconnectbutton = (Button) findViewById(R.id.Button02);
89 | disconnectbutton.setOnClickListener(new View.OnClickListener() {
90 | public void onClick(View v) {
91 | closeConnectionToServer();
92 | }
93 | });
94 |
95 | }
96 |
97 | @Override
98 | protected void onResume(){
99 | super.onResume();
100 |
101 | SharedPreferences prefs = getSharedPreferences(PREFS_NAME, 0);
102 |
103 | String ip = prefs.getString(IP_PREF, "192.168.1.2");
104 | String port = prefs.getString(PORT_PREF, "5554");
105 | String listener = prefs.getString(LISTENER_PORT_PREF, "5555");
106 |
107 | boolean useCap = prefs.getBoolean(USE_SCREEN_CAP_PREF, true);
108 | int framerate = prefs.getInt(FRAME_RATE_PREF, 10);
109 | float ratio = prefs.getFloat(SCREEN_RATIO_PREF, 1.0f);
110 |
111 | int sens = prefs.getInt(SENSITIVITY_PREF, 0);
112 |
113 | ipField.setText(ip);
114 | portField.setText(port);
115 | sensitivity.setProgress(sens);
116 |
117 | listenerPortField.setText(listener);
118 | frameRate.setText(framerate+"");
119 | useScreenCap.setChecked(useCap);
120 | screenRatio.setText(ratio+"");
121 |
122 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
123 | appDel.stopServer();
124 | }
125 |
126 | @Override
127 | protected void onPause(){
128 | super.onPause();
129 | }
130 |
131 |
132 |
133 | /***********************************************************************************
134 |
135 | Network and Server Status Alerts
136 |
137 | ***********************************************************************************/
138 |
139 | private void networkUnreachableAlert(){
140 | AlertDialog network_alert = new AlertDialog.Builder(this).create();
141 | network_alert.setTitle("Network Unreachable");
142 | network_alert.setMessage("Your device is not connected to a network.");
143 | network_alert.setButton("Ok", new DialogInterface.OnClickListener() {
144 | //@Override
145 | public void onClick(DialogInterface dialog, int which) {
146 | return;
147 | }
148 | });
149 | network_alert.show();
150 | }
151 |
152 | private void serverUnreachablealert(){
153 | AlertDialog alert = new AlertDialog.Builder(this).create();
154 | alert.setTitle("Server Connection Unavailable");
155 | alert.setMessage("Please make sure the server is running on your computer");
156 | alert.setButton("Ok", new DialogInterface.OnClickListener() {
157 | //@Override
158 | public void onClick(DialogInterface dialog, int which) {
159 | return;
160 | }
161 | });
162 |
163 | alert.show();
164 | }
165 |
166 |
167 |
168 | /***********************************************************************************
169 |
170 | Button Handlers used to connect to the server through the AppDelegate
171 |
172 | ***********************************************************************************/
173 |
174 | private void connectToServer() {
175 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
176 | if(!appDel.canAccessNetwork()){
177 | networkUnreachableAlert();
178 | return;
179 | }
180 |
181 | if(!appDel.connected()){
182 |
183 | String serverIp = ipField.getText().toString();
184 | int serverPort = Integer.parseInt(portField.getText().toString());
185 | int listenPort = Integer.parseInt(listenerPortField.getText().toString());
186 | int fps = Integer.parseInt(frameRate.getText().toString());
187 |
188 | appDel.createClientThread(serverIp, serverPort);
189 |
190 | if(useScreenCap.isChecked())
191 | {
192 | appDel.createScreenCaptureThread(listenPort, fps);
193 |
194 | }
195 | }
196 |
197 | //TODO find better way to check for connection to the server
198 | int x;
199 | for(x=0;x<4;x++){// every quarter second for one second check if the server is reachable
200 | if(appDel.connected()){
201 |
202 | Intent controller = new Intent(Touch.this, Controller.class);
203 | controller.putExtra("sensitivity" , Math.round( sensitivity.getProgress() /20) + 1);
204 | controller.putExtra("ratio" , Float.parseFloat(screenRatio.getText().toString()));
205 |
206 | startActivity( controller );
207 | x = 6;
208 | }
209 | try{Thread.sleep(250);}
210 | catch(Exception e){}
211 | }
212 | /////////////////////////////////////////////////////////////////////
213 |
214 |
215 |
216 | if(!appDel.connected())
217 | serverUnreachablealert();
218 | }
219 |
220 | private void closeConnectionToServer(){
221 | AppDelegate appDel = ((AppDelegate)getApplicationContext());
222 | appDel.stopServer();
223 | }
224 | }
225 |
--------------------------------------------------------------------------------