Theta4j Minimal Plug-in Example in Java


Yesterday, I wrote about an example from @shrhdk (Shiro) of using Kotlin to write a minimal plug-in. As Kotlin is new and I’m still learning Java, I decided to build an example in Java starting from a new empty activity, not from the plug-in SDK. This is like a “Hello, World” example for the plug-in that just takes a picture.


Unfortunately, I wasn’t able to add a simple theta.takePicture() command into
KeyCallback.onKeyDown and be finished with the example. Sadly, I needed to use ExecutorService.

private ExecutorService executor = Executors.newSingleThreadExecutor();

In onKeyDown, I needed to do this:

    public void onKeyDown(int keyCode, KeyEvent keyEvent) {
        if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
            // use lambda expression with Java 1.8
            executor.submit(() -> {
                Log.d("THETA", "take picture");
                try {
                } catch (IOException e) {

The above snippet was a little intimidating for me at first because I didn’t know what this line meant.

  executor.submit(() -> {

I skimmed this article on Lambda expressions and was able to figure out that it’s a shortcut for a Runnable in this case.

The only new concept is to put theta.takePicture() on a new thread. Wish it could be easier and just dump the entire KeyCallBack into onCreate or onResume, but that’s how it is.

Getting the pluginlibrary and theta4j libraries

As I started from a new empty Activity and not from the Plug-in SDK, I also needed to get the libraries with the gradle config files.

In build.gradle project

allprojects {
    repositories {
        maven { url '' }

In build.gradle app

dependencies {
     implementation 'com.theta360:pluginlibrary:2.0.0'
    implementation 'org.theta4j:theta-web-api:1.2.2'

I also added this:

android {
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8

Getting the Response

Shiro provides an example to get the response. I added it in a branch.

import org.theta4j.osc.CommandResponse;
import org.theta4j.osc.CommandState;
import org.theta4j.webapi.TakePicture;
CommandResponse<TakePicture.Result> response = theta.takePicture();
while(response.getState() != CommandState.DONE) {
    response = theta.commandStatus(response);
System.out.println("fileUrl: " + response.getResults().getFileUrl());

Setting Options

I have another branch to set the camera options. I received help from the developer of theta4j and I can now set CAPTURE_MODE, EXPOSURE_COMPENSATION, ISO, and EXPOSURE_PROGRAM.

The main section is listed below. It’s easy to set the options.

            theta.setOption(CAPTURE_MODE, CaptureMode.IMAGE);
            CaptureMode captureMode = theta.getOption(CAPTURE_MODE);
            Log.d(TAG, captureMode.toString());

            theta.setOption(EXPOSURE_COMPENSATION, ExposureCompensation.MINUS_1_0);
            ExposureCompensation exposureCompensation = theta.getOption(EXPOSURE_COMPENSATION);
            Log.d(TAG, exposureCompensation.toString());

            // make sure CaptureMode is set to IMAGE
            theta.setOption(EXPOSURE_PROGRAM, ExposureProgram.MANUAL);
            theta.setOption(ISO, _200);
            Log.d(TAG, "ISO Speed Changed: " + theta.getOption(ISO).toString());


For people like like to start with an empty activity, the bare minimal code, theta4j provides a good structure to access the THETA webAPI from inside the camera. The only funky part for some people will be the need to use a separate thread. Once you get by that hurdle, accessing the rest of the API looks straightforward.

Using theta4j Library to Build a RICOH THETA Plug-in from Scratch in 80 minutes

@codetricity Thanks for posting this. I like the idea of working from a blank project.

As a first step, I download the zipped up repo from GitHub, imported into Android Studio, built the apk, installed it in my THETA V, set it as the primary plug-in using the RICOH desktop app (on using a mid 2010 iMac running macOS 10.13.6 and the RICOH THETA desktop app is Version 3.9.0).


It works!

Just for fun, I went through and renamed the project to helloworld, changed the icon, and changed the Hello World! text.

New name:


New icon:

New Hello World! text (click on the image to get a bigger image):

And, yea, it still works:


Nice. Note that there are four branches on the repo:

  • master - the minimal needed
  • response branch shows how to get the camera HTTP response from the WebAPI command. It shows how to receive the URI for the last picture taken.
  • options branch shows to to get and set camera settings. ISO, exposure compensation, capture mode.
  • indicators branch shows use of a camera beep and magenta LED to show the start of a multi-picture loop.