I am trying to develop a android remote control code for playing presentation. The project is divided into two parts:
- Socket Server We need to start the server and wait for clients to connect.When the client sends the commands the server processes the command using Robot.KeyPress
- Mobile Application (Socket Client) This is an mobile application which sends some commands to the server like "F5".
The current code works fine in android phones with updates upto Marshmallow (tried on Lollipop and Marshmallow) but when tried the same code on Nougat the app is crashing (Android Remote has stopped, Open app again).
Socket Server Code:
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.MouseInfo;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class RemoteDroidServer {
private static ServerSocket server = null;
private static Socket client = null;
private static BufferedReader in = null;
private static String line;
private static boolean isConnected=true;
private static Robot robot;
private static final int SERVER_PORT = 8998;
public static void main(String[] args) {
boolean leftpressed=false;
boolean rightpressed=false;
try{
robot = new Robot();
server = new ServerSocket(SERVER_PORT); //Create a server socket on port 8998
client = server.accept(); //Listens for a connection to be made to this socket and accepts it
in = new BufferedReader(new InputStreamReader(client.getInputStream())); //the input stream where data will come from client
System.out.println("Connected to server");
}catch (IOException e) {
System.out.println("Error in opening Socket");
System.exit(-1);
}catch (AWTException e) {
System.out.println("Error in creating robot instance");
System.exit(-1);
}
//read input from client while it is connected
while(isConnected){
try{
line = in.readLine(); //read input from client
System.out.println(line); //print whatever we get from client
//-----------------VLC Commands--------------------------------
/*
Space Bar to Play or Pause. ...
F to toggle Full Screen. ...
A to Change Aspect ratio. ...
Z to Change Zoom Mode. ...
Ctrl+RightArrow to move forward
Ctrl+LeftArrow to move backward
Alt+Left/Alt+Right to Fast Forward slow. ...
*/
//if user clicks on fullscreen (Key- F)
if(line.equalsIgnoreCase("fullscreen")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_F);
robot.keyRelease(KeyEvent.VK_F);
}
//if user click on Change Aspect ratio (Key- A)
if(line.equalsIgnoreCase("aspectratio")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_A);
robot.keyRelease(KeyEvent.VK_A);
}
//if user clicks on Increase Volume (CTRL + UpArrowKey)
if(line.equalsIgnoreCase("volplus")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_UP);
// CTRL+UpArrowKey is now pressed (receiving application should see a "key down" event.)
robot.keyRelease(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
//if user clicks on Decrease Volume (CTRL + DownArrowKey)
if(line.equalsIgnoreCase("volminus")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_DOWN);
// CTRL+DownArrowKey is now pressed (receiving application should see a "key down" event.)
robot.keyRelease(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
//if user clicks on move forward (CTRL + RightArrow)
if(line.equalsIgnoreCase("forward")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_RIGHT);
// CTRL+UpArrowKey is now pressed (receiving application should see a "key down" event.)
robot.keyRelease(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
//if user clicks on move forward (CTRL + LeftArrow)
if(line.equalsIgnoreCase("backward")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_LEFT);
// CTRL+UpArrowKey is now pressed (receiving application should see a "key down" event.)
robot.keyRelease(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_LEFT);
}
//-------------------------------------------------------------
//if user clicks on f5
if(line.equalsIgnoreCase("F5")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_F5);
robot.keyRelease(KeyEvent.VK_F5);
}
//if user clicks on esc
if(line.equalsIgnoreCase("escape")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_ESCAPE);
robot.keyRelease(KeyEvent.VK_ESCAPE);
}
//if user clicks on first slide
if(line.equalsIgnoreCase("home")){
//Simulate press and release of key 'Home'
robot.keyPress(KeyEvent.VK_HOME);
robot.keyRelease(KeyEvent.VK_HOME);
}
//if user clicks on last slide
if(line.equalsIgnoreCase("end")){
//Simulate press and release of key 'END'
robot.keyPress(KeyEvent.VK_END);
robot.keyRelease(KeyEvent.VK_END);
}
//----------------------------------------------------------------------------
//if user clicks on next
if(line.equalsIgnoreCase("next")){
//Simulate press and release of key 'n'
robot.keyPress(KeyEvent.VK_N);
robot.keyRelease(KeyEvent.VK_N);
}
//if user clicks on previous
else if(line.equalsIgnoreCase("previous")){
//Simulate press and release of key 'p'
robot.keyPress(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_P);
}
//if user clicks on play/pause
else if(line.equalsIgnoreCase("play")){
//Simulate press and release of spacebar
robot.keyPress(KeyEvent.VK_SPACE);
robot.keyRelease(KeyEvent.VK_SPACE);
}
//input will come in x,y format if user moves mouse on mousepad
else if(line.contains(",")){
float movex=Float.parseFloat(line.split(",")[0]);//extract movement in x direction
float movey=Float.parseFloat(line.split(",")[1]);//extract movement in y direction
Point point = MouseInfo.getPointerInfo().getLocation(); //Get current mouse position
float nowx=point.x;
float nowy=point.y;
robot.mouseMove((int)(nowx+movex),(int)(nowy+movey));//Move mouse pointer to new location
}
//if user taps on mousepad to simulate a left click
else if(line.contains("left_click")){
//Simulate press and release of mouse button 1(makes sure correct button is pressed based on user's dexterity)
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
//Exit if user ends the connection
else if(line.equalsIgnoreCase("exit")){
isConnected=false;
//Close server and client socket
server.close();
client.close();
}
} catch (IOException e) {
System.out.println("Read failed");
System.exit(-1);
}
}
}
}
My Android Code is :
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class Powerpoint extends AppCompatActivity implements View.OnClickListener{
Context context;
Button esc;
Button nextButton;
Button previousButton;
Button end;
Button btnConnect;
Button f5;
Button home;
private boolean isConnected=false;
private boolean mouseMoved=false;
private Socket socket;
private PrintWriter out;
private String serverIP= Constants.SERVER_IP;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_powerpoint);
context = this; //save the context to show Toast messages
//Get references of all buttons
esc = (Button)findViewById(R.id.btnEnd);
nextButton = (Button)findViewById(R.id.btnNext);
previousButton = (Button)findViewById(R.id.btnPrevious);
f5 = (Button)findViewById(R.id.btnStart);
btnConnect = (Button)findViewById(R.id.btnConnect);
home = (Button)findViewById(R.id.btnHome);
end = (Button)findViewById(R.id.btnLastSlide);
//this activity extends View.OnClickListener, set this as onClickListener
//for all buttons
esc.setOnClickListener(this);
nextButton.setOnClickListener(this);
previousButton.setOnClickListener(this);
f5.setOnClickListener(this);
home.setOnClickListener(this);
end.setOnClickListener(this);
btnConnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// get prompts.xml view
LayoutInflater li = LayoutInflater.from(context);
View promptsView = li.inflate(R.layout.prompt, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
// set prompts.xml to alertdialog builder
alertDialogBuilder.setView(promptsView);
final EditText userInput = (EditText) promptsView
.findViewById(R.id.editTextDialogUserInput);
// set dialog message
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// get user input and set it to result
// edit text
serverIP=userInput.getText().toString();
Toast.makeText(getApplicationContext(),"Ip:"+serverIP,Toast.LENGTH_SHORT).show();
ConnectPhoneTask connectPhoneTask = new ConnectPhoneTask();
connectPhoneTask.execute(serverIP); //try to connect to server in another thread
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
});
}
//OnClick method is called when any of the buttons are pressed
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnEnd:
if (isConnected && out!=null) {
out.println(Constants.ESCAPE);//send "escape" to server
}
break;
case R.id.btnNext:
if (isConnected && out!=null) {
out.println(Constants.NEXT); //send "next" to server
}
break;
case R.id.btnPrevious:
if (isConnected && out!=null) {
out.println(Constants.PREVIOUS); //send "previous" to server
}
break;
case R.id.btnStart:
if (isConnected && out!=null) {
out.println(Constants.F5); //send "previous" to server
}
break;
case R.id.btnHome:
if (isConnected && out!=null) {
out.println(Constants.HOME); //send "home" to server
}
break;
case R.id.btnLastSlide:
if (isConnected && out!=null) {
out.println(Constants.END); //send "end" to server
}
break;
}
}
@Override
public void onDestroy()
{
super.onDestroy();
if(isConnected && out!=null) {
try {
out.println("exit"); //tell server to exit
socket.close(); //close socket
} catch (IOException e) {
Log.e("remotedroid", "Error in closing socket", e);
}
}
}
public class ConnectPhoneTask extends AsyncTask<String,Void,Boolean> {
@Override
protected Boolean doInBackground(String... params) {
boolean result = true;
try {
InetAddress serverAddr = InetAddress.getByName(params[0]);
socket = new Socket(serverAddr, Constants.SERVER_PORT);//Open socket on server IP and port
isConnected=true;
} catch (IOException e) {
Log.e("remotedroid", "Error while connecting", e);
result = false;
isConnected=false;
}
return result;
}
@Override
protected void onPostExecute(Boolean result)
{
isConnected = result;
Toast.makeText(context, isConnected ? "Connected to server!" : "Error while connecting", Toast.LENGTH_LONG).show();
try {
if(isConnected) {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket
.getOutputStream())), true); //create output stream to send data to server
}
}catch (IOException e){
Log.e("remotedroid", "Error while creating OutWriter", e);
Toast.makeText(context,"Error while connecting",Toast.LENGTH_LONG).show();
}
}
}
}
Constants Class code:
public class Constants {
public static final String SERVER_IP = "192.168.1.5";
public static final int SERVER_PORT = 8998;
public static final String NEXT="next";
public static final String PREVIOUS="previous";
public static final String ESCAPE="escape";
public static final String F5="f5";
public static final String HOME="home";
public static final String END="end";
public static final String SPACE="play";
public static final String VOLUP="volplus";
public static final String VOLDOWN="volminus";
public static final String FASTFORWARD="forward";
public static final String BACKWARD="backward";
public static final String ZOOM="fullscreen";
public static final String ASPECTRATIO="aspectratio";
}
Layout File:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_powerpoint"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.sahajsolns.socketprogrammingdemo.Powerpoint">
<Button
android:text="Start PPT"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="48dp"
android:id="@+id/btnStart"
android:layout_below="@+id/lblModuleTitle"
android:layout_centerHorizontal="true" />
<TextView
android:text="Powerpoint Module"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="45dp"
android:id="@+id/lblModuleTitle"
android:textSize="18sp"
android:textColor="@android:color/holo_orange_dark"
android:textStyle="normal|bold"
android:lineSpacingExtra="8sp" />
<Button
android:text="Next Slide"
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/btnNext"
android:layout_below="@+id/btnStart"
android:layout_toRightOf="@+id/btnStart"
android:layout_toEndOf="@+id/btnStart" />
<Button
android:text="End PPT"
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/btnEnd"
android:layout_below="@+id/btnNext"
android:layout_toRightOf="@+id/btnPrevious"
android:layout_toEndOf="@+id/btnPrevious" />
<Button
android:text="Previous Slide"
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/btnPrevious"
android:layout_below="@+id/btnStart"
android:layout_toLeftOf="@+id/btnStart"
android:layout_toStartOf="@+id/btnStart" />
<Button
android:text="Connect To Server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:id="@+id/btnConnect" />
<Button
android:text="Home"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_below="@+id/btnPrevious"
android:layout_toLeftOf="@+id/btnEnd"
android:layout_toStartOf="@+id/btnEnd"
android:id="@+id/btnHome" />
<Button
android:text="Last Slide"
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/btnLastSlide"
android:layout_below="@+id/btnNext"
android:layout_toRightOf="@+id/btnEnd"
android:layout_toEndOf="@+id/btnEnd" />
</RelativeLayout>