you're reading...
Android, How-to's

HTTYR: Android Control App

This post is part of a series on how to train your robot.

The application described here needs a Wifi dongle and leJOS Ev3 0.9.0 or above.

Creating Android apps in Eclipse is easy, and using the RemoteRequestEV3 class in leJOS 0.9.0, makes it easy to control your EV3 from an Android app.

Once you have installed the Android SDK and installed Android support in Eclipse, you can create a new Android app by File > New > Android Application Project.


Fill in the application name, project name and the package name and press Next.

Take the defaults, on all the screens to get a blank activity called MainActivity and a layout called activity_main. You can choose a background color on the third screen. Feel free to experiment with the other options.

Once you have your application in Eclipse, you should edit AndroidManifest.xml to allow network access. Add the following to near the start of the manifest file:

<uses-permission android:name="android.permission.INTERNET" />

You will also need to add a reference to the ev3classes project or the ev3classes.jar library in your project’s Properties > Java Build Path. You should check the export check next to ev3classes in the Export and Order tab.

We will create an app with 5 buttons to move a differential drive robot (such as TRACK3R) around, and a button to connect to or disconnect from the EV3.

Here is the modified layout/activity_main.xml file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    tools:context=".MainActivity" >

        android:text="@string/right" />

        android:text="@string/left" />

        android:text="@string/backward" />

        android:text="@string/forward" />

        android:text="@string/stop" />

        android:text="@string/connect" />


You will also need to modify the values/strings.xml file to define the text for the buttons, e.g. @string/connect, etc..

We will use an Android async task to connect to the EV3 as that is the recommended way to do network access.

The modified MainActivity.java file is as follows. You will need to change the package name to the one you used.

package org.lejos.android.sample.control;

import java.io.IOException;

import lejos.hardware.Audio;
import lejos.remote.ev3.RemoteRequestEV3;
import lejos.robotics.RegulatedMotor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	private RemoteRequestEV3 ev3;
	private RegulatedMotor left, right;
	private Button connect;
	private Audio audio;

	protected void onCreate(Bundle savedInstanceState) {

		Button left = (Button) findViewById(R.id.left);
		Button right = (Button) findViewById(R.id.right);
		Button stop = (Button) findViewById(R.id.stop);
		Button forward = (Button) findViewById(R.id.forward);
		Button backward = (Button) findViewById(R.id.backward);
		connect = (Button) findViewById(R.id.connect);

	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;

	public void onClick(View v) {
		if (v.getId() == R.id.left) new Control().execute("rotate left");
		else if (v.getId() == R.id.right) new Control().execute("rotate right");
		else if (v.getId() == R.id.stop) new Control().execute("stop");
		else if (v.getId() == R.id.forward) new Control().execute("forward");
		else if (v.getId() == R.id.backward) new Control().execute("backward");
		else if (v.getId() == R.id.connect) {
			if (ev3 == null) {
				new Control().execute("connect","");
			else {
				new Control().execute("disconnect");

	private class Control extends AsyncTask<String, Integer, Long> {

		 protected Long doInBackground(String... cmd) {

			 if (cmd[0].equals("connect")) {
				try {
					ev3 = new RemoteRequestEV3(cmd[1]);
					left = ev3.createRegulatedMotor("A", 'L');
					right = ev3.createRegulatedMotor("B", 'L');
					audio = ev3.getAudio();
					return 0l;
				} catch (IOException e) {
					return 1l;
			 } else if (cmd[0].equals("disconnect") && ev3 != null) {
				 ev3 = null;
				 return 0l;

			 if (ev3 == null) return 2l;


			 if (cmd[0].equals("stop")) {
			 } else if (cmd[0].equals("forward")) {
			 } else if (cmd[0].equals("backward")) {
			 } else if (cmd[0].equals("rotate left")) {
			 } else if (cmd[0].equals("rotate right")) {

			 return 0l;

	     protected void onPostExecute(Long result) {
	    	 if (result == 1l) Toast.makeText(MainActivity.this, "Could not connect to EV3", Toast.LENGTH_LONG).show();
	    	 else if (result == 2l) Toast.makeText(MainActivity.this, "Not connected", Toast.LENGTH_LONG).show();


Change the host name in the application to the IP address of your EV3.

To create a .apk file that you can install on your Android phone or tablet, you can right-click o the project and choose Export Signed Application Package… from the Android Tools menu. You can then copy the file to your Android device and install it by selecting the Package Installer. You may have to change your settings to allow .apk files to be installed.

If your EV3 has the leJOS EV3 Menu program, running, you can now connect to it, and drive it around using your Android device.

Happy driving!



33 thoughts on “HTTYR: Android Control App

  1. Great example, would really like to get this working.

    Didn’t get Eclipse to get the above MainActivity.java working yet. I’ve used the EV3 0.8.1-beta Lejos release (as of date, there is no 0.9 for EV3 as suggested in the blog). In the code, the RemoteRequestEV3 class is used. That class is not present in the 0.8.1 version in the ev3classes.jar. There is a RemoteEV3 present, but it does not seem to cover the functionality needed by the Control class. What am I missing?

    Posted by GrinningHermit | 2014/05/08, 09:02
    • The 0.9.0 release it not out yet. If you want to try this now, you will need to use the latest version of ev3classes and EV3Menu from Git. They are currently still compatible with the 0.8.1 sd card. To use them, you need to check the latest versions out of the Git ev3 repository, and build the with their ant build files, and then restart the EV3.

      RemoteEV3 does not work with Android, as Android does not support Java RMI. That is why I have now implemented RemoteRequestMenu.

      The 0.9.0 release should be out soon. We are currently making it work with Java 8.

      Posted by Geek Grandad | 2014/05/08, 12:10
      • Can you post the link to the leJOS EV3 0.9.0 GIT Repo??

        would be great because i can not find it…

        Posted by Tozu | 2014/06/26, 07:40
  2. Thank you for the reply. I think I’ll wait on version 0.9 then. I have no experience with ant and it gave a lot of errors on my attempts to build the files. It seemed like some packages were missing. Good luck with the wonderful stuff you are creating and I hope to find the new version soon!

    Posted by GrinningHermit | 2014/05/12, 14:58
  3. I’m trying to get this to work over a Bluetooth connection (for reasons) and getting various errors (permission denied/connection time out) depending on what permissions I put in the Manifest. The EV3 has successfully paired with both the computer I’m running the emulator on, and the android device I’m testing it with.

    Any suggestions?

    Posted by louisedennisouise Dennis | 2015/03/20, 17:57
    • The application is using a TCP/IP connection. To use that over Bluetooth, you need the Android device to connect to a Bluetooth PAN. I don’t believe most of them can do that.

      The application could be rewritten to use a Bluetooth serial (SPP) connection, but leJOS support for Bluetooth SPP is very limited, partly because Java support for Bluetooth SPP is poor and unmaintained.

      Posted by Geek Grandad | 2015/03/20, 18:31
      • This might be relevant for some Android devices – http://android.stackexchange.com/questions/12572/are-there-any-android-phones-that-allow-bluetooth-pan-off-the-shelf/29089#29089.

        You need the device to be a PAN client, not host.

        Posted by Geek Grandad | 2015/03/20, 18:38
      • Thanks! I was working with a Nexus 7 tablet, though we would like the final target to be something a bit cheaper (e.g., a Samsung tablet). Poking around the internet suggests this ought to be possible on the Nexus, it’s less clear about Samsungs.

        We may just opt for PC->EV3 connection since that definitely works even if it won’t look quite as good and won’t have the same battery life as a tablet->EV3 connection.

        Posted by Louise Dennis | 2015/03/21, 09:39
      • Thanks also for that link about Android Bluetooth PAN. That looks hopeful. I will investigate. If it looks feasible but just isn’t quite supported by RequestResponseEV3 we can always try tweaking that class – it doesn’t look too complex.

        Posted by Louise Dennis | 2015/03/21, 10:52
    • See my post below about the post 0.9.0 release

      Posted by gloomyandy | 2015/03/20, 19:03
  4. The next release (post 0.9.0) of leJOS includes options in the menu that allows an EV3 to be a Bluetooth Client (PANU mode) to a PAN access point or to establish an ad hoc connection. So if your phone can run as a Bluetooth PAN AP (some can) or can handle ad hoc connections, then this new mode may help. For instance this mode can be used to allow an EV3 to connect to a Windows PC (Which can not usually act as a PAN AP, but can accept ad hoc connections). Note however that this has not been tested with an Android device.

    Posted by gloomyandy | 2015/03/20, 19:02
    • Any idea when this is likely to appear? We’ve a hard deadline of 1st week of June but have other options for the set up. Bluetooth between a PC and EV3 definitely works, and as an alternative we could attempt to set up a small local wifi network, though I’m not keen to go down that route. It’s really a matter, at this point, of figuring out where best to invest my time.

      Posted by Louise Dennis | 2015/03/21, 09:41
  5. Please help me….Here https://drive.google.com/open?id=0BwuUKw0gKDGwNmJHWGNMS05JNUU&authuser=0 you can find images 1 to 5 that describe my configuration of my project …i get this error but as you can see on image5 i find the class that error tell me that is not finded…help me please…

    “04-15 22:27:10.880: E/dalvikvm(6052): Could not find class ‘lejos.remote.ev3.RemoteRequestEV3’, referenced from method com.example.pasapapelandroid.MainActivity$Control.doInBackground”

    Posted by Franklin | 2015/04/15, 22:48
    • You need to use the 0,9.0 release.

      Posted by Lawrie Griffiths | 2015/04/16, 09:13
      • Yes… I am work ing With this version

        Posted by Franklin | 2015/04/16, 10:10
      • You seem to have the project as a leJOS EV3 plugin project. I don’t know if that will work – I have not tried it. You should try referencing ev3classes.jar directly (or reference the ev3classes project downloaded from Git). Make sure you have it marked as exported in Order and Export.

        Posted by Lawrie Griffiths | 2015/04/16, 11:22
  6. Hi, I want to work with the Ev3TouchSensor and when I’m going to initialize new EV3TouchSensor(ev3.getPort(“S1”) ,throws the following exception:

    java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:300)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:841)
    Caused by: java.lang.NullPointerException
    at lejos.remote.ev3.RemoteRequestAnalogPort.setPinMode(RemoteRequestAnalogPort.java:75)
    at lejos.remote.ev3.RemoteRequestAnalogPort.setType(RemoteRequestAnalogPort.java:47)
    at lejos.remote.ev3.RemoteRequestIOPort.setTypeAndMode(RemoteRequestIOPort.java:54)
    at lejos.hardware.sensor.AnalogSensor.(AnalogSensor.java:25)
    at lejos.hardware.sensor.AnalogSensor.(AnalogSensor.java:35)
    at lejos.hardware.sensor.EV3TouchSensor.(EV3TouchSensor.java:61)
    at org.lejos.android.sample.control.MainActivity$Control.doInBackground(MainActivity.java:91)
    at org.lejos.android.sample.control.MainActivity$Control.doInBackground(MainActivity.java:76)
    at android.os.AsyncTask$2.call(AsyncTask.java:288)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                at java.lang.Thread.run(Thread.java:841)

    Posted by Alberto | 2015/05/06, 12:11
    • There is a bug in lejos.remote.ev3.RemoteRequestAnalogPort. The second parameter to sendRequest in setPinMode at line 75 should be true, not false. You can either rebuild ev3classes, or you could try using the createSampleProvider method of RemoteRequestEV3.

      How did you get the error report?

      Posted by Lawrie Griffiths | 2015/05/06, 15:47
  7. I am doing a project in AndroiStudio and I get error report of the ADB logcat console connected to the Mobile phone. I tried createSampleProvider and throws me:
    Caused by: lejos.remote.ev3.RemoteRequestException: java.io.InvalidClassException: java.lang.ReflectiveOperationException; Incompatible class (SUID): java.lang.ReflectiveOperationException: static final long serialVersionUID =123456789L; but expected java.lang.ReflectiveOperationException: static final long serialVersionUID =2505831918131413020L;

    I am a novice at this. Sorry..

    Posted by Alberto | 2015/05/06, 16:39
    • There is some problem with the exception handling. This stuff has not been tested much.

      The following works for me:


      private RemoteRequestSampleProvider sp;

      In connect task, do:

      sp = (RemoteRequestSampleProvider) ev3.createSampleProvider(“S1”, “lejos.hardware.sensor.EV3TouchSensor”, “Touch”);

      In disconnect task, before the other closes, do:

      if (sp != null) sp.close();

      I have not tried using it, but I assume that will work.

      Posted by Lawrie Griffiths | 2015/05/06, 19:48
      • Thanks Lawrie, work the first time, then throws:
        Caused by: lejos.remote.ev3.RemoteRequestException: java.io.InvalidClassException: java.lang.ReflectiveOperationException; Incompatible class (SUID): java.lang.ReflectiveOperationException: static final long serialVersionUID =123456789L; but expected java.lang.ReflectiveOperationException: static final long serialVersionUID =2505831918131413020L;

        I have to restart the brick to get it working again, I do the closing sp as you said but somethings is wrong.

        Posted by Alberto | 2015/05/07, 09:56
      • It worked for me multiple times as long as I always disconnected and executed a close. The sp.close() did not work if it was the last things before executing disConnect as the disconnect seemed to happen before the close completed. You can see the actual error on the EV3 if you connect to it with EV3Control and look at the Console tab.

        Posted by Lawrie Griffiths | 2015/05/07, 11:26
      • Yes, solved. I used Thread.sleep(1000); before disConnect() and works but I don´t know if that’s right. Thanks!

        Posted by Alberto | 2015/05/07, 12:39
  8. Hello, android java.rmi not support and can not use RMIMenu. What I have to do? RemoteRequestMenu not work for me.

    Posted by Alberto | 2015/05/11, 13:20
    • Now I got to get the menu RemoteRequestMenu brick being disconnected. You can not be connected and get the menu? Thank you.

      Posted by Alberto | 2015/05/12, 16:04
      • I think the remote request system currently only supports a single connection which can either be a menu or an EV3 connection. It needs improvement.

        Posted by Lawrie Griffiths | 2015/05/12, 20:59
  9. Hi! does not the method ev3.getAudio().playSample(new File(“/home/lejos/programs/” + fileName)); from Android app with class RemoteRequestEV3. Of getAudio() only works systemSound() .
    From the desktop ControlEv3 if it work.
    Anyone know how to fix it? Thanks.

    Posted by Alberto | 2015/05/14, 09:55
    • The problem is that PLAY_SAMPLE was never implemented in the menu (sorry!). EV3Menu needs the following adding:

      case PLAY_SAMPLE:
      reply.reply = Sound.playSample(request.file);

      after the SYSTEM_SOUND case at about line 1017.

      It is quite easy to rebuild the menu. You just need to get the 0.9.0 source from git, create or edit local.properties to set ev3.host= and run the build.xml file. This should rebuild the menu and upload it to the EV3. You should then restart the EV3, and PLAY_SAMPLE should then work. It did for me.

      Posted by Lawrie Griffiths | 2015/05/16, 16:41
  10. How to get this to work with Android Studio? I gave it a shot, but Android Studio was unable to find any of the EV3 Classes or links to LeJOS.

    Posted by sarangborude | 2016/01/26, 20:29
    • I have not used Android Studio yet – I still use Eclipse for Android development. Using leJOS should be similar to using any other external project or library, but I don’t know how you do that in Android Studio. In Eclipse I created a source project for ev3classes and referenced that, but a reference to the ev3classes.jar file should work.

      Posted by Lawrie Griffiths | 2016/03/02, 09:36
  11. Hello. I tried to implement this project. I’ve made everything as in the instructions, changed IP, added to the manifest, built the pass to the libraries, but when I push the connect buttom the app crashes and exites. In the log file there are errors that can’t find remote classes.

    04-07 22:56:25.370: E/AndroidRuntime(1637): FATAL EXCEPTION: AsyncTask #1
    04-07 22:56:25.370: E/AndroidRuntime(1637): Process: dmitry.khramov.project1_testcontrol, PID: 1637
    04-07 22:56:25.370: E/AndroidRuntime(1637): java.lang.RuntimeException: An error occured while executing doInBackground()
    04-07 22:56:25.370: E/AndroidRuntime(1637): at android.os.AsyncTask$3.done(AsyncTask.java:304)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.Thread.run(Thread.java:818)
    04-07 22:56:25.370: E/AndroidRuntime(1637): Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Llejos/remote/ev3/RemoteRequestEV3;
    04-07 22:56:25.370: E/AndroidRuntime(1637): at dmitry.khramov.project1_testcontrol.MainActivity$Control.doInBackground(MainActivity.java:76)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at dmitry.khramov.project1_testcontrol.MainActivity$Control.doInBackground(MainActivity.java:1)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at android.os.AsyncTask$2.call(AsyncTask.java:292)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    04-07 22:56:25.370: E/AndroidRuntime(1637): … 4 more
    04-07 22:56:25.370: E/AndroidRuntime(1637): Caused by: java.lang.ClassNotFoundException: Didn’t find class “lejos.remote.ev3.RemoteRequestEV3” on path: DexPathList[[zip file “/data/app/dmitry.khramov.project1_testcontrol-1/base.apk”],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
    04-07 22:56:25.370: E/AndroidRuntime(1637): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
    04-07 22:56:25.370: E/AndroidRuntime(1637): … 8 more
    04-07 22:56:25.370: E/AndroidRuntime(1637): Suppressed: java.lang.ClassNotFoundException: lejos.remote.ev3.RemoteRequestEV3
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.Class.classForName(Native Method)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
    04-07 22:56:25.370: E/AndroidRuntime(1637): at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
    04-07 22:56:25.370: E/AndroidRuntime(1637): … 9 more
    04-07 22:56:25.370: E/AndroidRuntime(1637): Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
    04-07 22:56:25.371: E/AndroidRuntime(1637): Error reporting crash
    04-07 22:56:25.371: E/AndroidRuntime(1637): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
    04-07 22:56:25.371: E/AndroidRuntime(1637): at android.os.Handler.(Handler.java:200)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at android.os.Handler.(Handler.java:114)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at android.content.AsyncQueryHandler.(AsyncQueryHandler.java:125)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at net.oneplus.odm.insight.tracker.AbstractTracker$TrackerAsyncQueryHandler.(AbstractTracker.java:108)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at net.oneplus.odm.insight.tracker.AbstractTracker.(AbstractTracker.java:60)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at net.oneplus.odm.insight.tracker.AppTracker.(AppTracker.java:24)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:97)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
    04-07 22:56:25.371: E/AndroidRuntime(1637): at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)

    Can you help me to solve this problem. I’m connectig with wi-fi, and using leJOS 0.9.1 version.

    Posted by Dmitry | 2016/04/07, 21:04
  12. Does this work on Android Studio also?

    Posted by Syafiq | 2016/10/19, 14:29

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

About leJOS News

leJOS News keeps you up-to-date with leJOS. It features latest news, explains cool features, shows advanced techniques and highlights amazing projects. Be sure to subscribe to leJOS News and never miss an article again. Best of all, subscription is free!
Follow leJOS News on WordPress.com
%d bloggers like this: