I have some programming background but I’m more of a power user than power programmer. I think there are a lot of people like me who use the RICOH THETA 360 degree camera. The THETA is a fantastic camera to program and extend, and I’ve seen many interesting use cases for both industry (construction, real estate, used car sales, virtual tours/tourism) and well as fun hobbies (the Meow Shot! plug-in makes the camera meow out loud and take a picture when your pet cat comes close).
I’ve wanted to program a plug-in myself cause I have a couple ideas on how I could make something useful and easy to use. But this is cutting-edge hardware. THETA has sophisticated lens and sensors, at least two different APIs, and no screen to help with testing. I was worried it could be slow going for me to build a plug-in for it.
I was wrong!
With the help of @codetricity and Shiro Hideki’s extremely useful theta4j library built for the THETA, I started with a blank screen, and was able to quickly move to building a functioning plug-in for the THETA. I found this method easier than going through the SDK or the 25 sample plug-ins listed in the THETA Plug-in Development Getting Started Guide.
The result is my new “Pretty Picture” plug-in, that I am submitting to the Plug-in Store today. It’s aimed at people who don’t want to use a mobile phone with the THETA (I believe this is common) and who want to be able to tell at a glance if there’s a picture being taken or what’s going on. It takes 4 pictures in a row, so you can pick the best one. It has a unique, pretty pink Wi-Fi icon while the plug-in is on. You’ll never be confused. And that pink icon is blinking when pictures are being taken. You can place the THETA somewhere for taking pictures and still know its status. Simple, clear, easy!
It was super cool to be able to think through how someone really uses the camera and build a plug-in to make that even easier. By starting with a completely empty project in Android Studio, I was able to get a clear understanding of the simple commands to control the LEDs, take pictures, and detect button presses.
Example image from my Pretty Picture plug-in, built in 80 minutes
My Technique Will Work For You, Too
Practicing a technique over and over - like a Kata in a martial art - will make you proficient. Practice, practice, practice. In the next sections, I have written down the exact steps to create a THETA plug-in from scratch. Follow the steps in this tutorial and you will be able to build a fully functioning plug-in.
Once you follow the steps and have a plug-in, you’ll be able to take pictures, change the UX by changing LED actions like color, on/off, blinking, add audio and more.
Sticking with the idea from martial arts, I have broken the step for building a plug-in into 4 different Katas.
- Kata 1 imports the RICOH pluginlibrary, creates a plug-in that changes the color of an LED and adds an audio cue
- Kata 2 creates a CallBack function that allows you to use the shutter button
- Kata 3, Part 1, sets up the theta4j library
- Kata 3, Part 2, uses the theta4j library to take a picture and that start to take a single picture, take multiple pictures (using a while loop), add sounds, add different LED actions
Kata 1: LED, Audio with plugins library
-
Create new Android Project in Android Studio
- For Choose your project, choose Empty Activity
- Set a name
- Set minimum API Level to be API 25: Android 7.1.1 (Nougat)
-
You need to add the RICOH plugin library
-
In Gradle app add
implementation 'com.theta360:pluginlibrary:2.0.0'
- Android Studio will ask you to Sync Now. Wait until you do the next step.
-
In Gradle project, set Maven repository under allprojects
maven { url 'https://github.com/ricohapi/theta-plugin-library/raw/master/repository' }
- Click Sync Now.
-
In MainActivity.java, change AppCompatActivity to PluginActivity
-
Then click on PluginActivity and do Alt-Enter and choose Import Class. Android Studio will automatically install PluginActivity. This line will appear on Line 6:
-
import com.theta360.pluginlibrary.activity.PluginActivity;
-
-
Set plug-in to automatically close and finish by adding
setAutoClose(true);
in onCreate -
Press Run app button to install plug-in in camera
- Make sure your THETA is connected by USB and is powered on.
- Android Studio will ask to Set Deployment Target. You should see QUALCOMM RICOH THETA V listed. Select OK.
-
Set the boot plug-in with desktop app
-
Unplug your THETA, put it in Plug-in mode by pressing and holding the Mode Button down for more than 2 seconds
-
Keep in Plugin Mode when re-attaching USB cable
-
Test with Vysor to see if properly running
- Vysor will show a Hello World! screen and the name of your plug-in will be in the green bar near the top.
-
Turn on LedTarget.LED3 (Wi-Fi icon) by adding the following to onCreate:
notificationLed3Show(LedColor.MAGENTA);
-
Test by pressing Run app button in Android Studio, do not need to unplug USB
- Since your plug-in is set as the boot plug-in and you’re already in Plug-in Mode and your plug-in currently starts up and the one thing it does is set LED3 to MAGENTA, as soon as it finishes building, you should see the Wi-Fi icon turn to a nice pink (magenta) color.
-
Change color of LED3
notificationLed3Show(LedColor.CYAN);
-
Test (same technique as Step #12)
-
Make LED3 blink
-
You can not copy and paste this new notification. You must type in LedTarget, LedColor, and for blink rate, type in number and “period” will be added
-
notificationLedBlink(LedTarget.LED3,LedColor.RED,period:500);
-
-
Test (same technique as Step #12)
-
Turn on LED4 (camera icon) and LED5 (video icon)
- You can turn LED4 and LED5 on and off, and you can make them blink (I’m not doing that here) but you can’t change their color
notificationLedShow(LedTarget.LED4);
notificationLedShow(LedTarget.LED5);
-
Test (same technique as Step #12)
-
Add sound
notificationAudioWarning();
-
Test (same technique as Step #12)
Kata 2: Button Press with KeyCallback
-
Create a keyCallBack function, to be able to read the Shutter button press
-
Create a class in PluginActivity
- Type it in, don’t copy and paste the code from here
-
-
private KeyCallback keyCallback = new KeyCallback() {
-
onKeyDown
,onKeyUp
, andonKeyLongPress
will be created automatically -
You will need to add an ;
-
Suggest commenting out LED colors for testing
-
Add LED color under onKeyDown
-
Need to instantiate, so add @Override below onCreate
@Override protected void onResume() { super.onResume(); setKeyCallback(keyCallback); }
-
Test
Kata 3: Using theta4j to Take a Picture
theta4j Part 1: Set Up theta4j
-
Install and configure theta4j
-
Implement theta4j in Gradle app file
-
implementation 'org.theta4j:theta-web-api:1.2.2'
-
-
Below buildTypes, add
compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 }
-
In AndroidManifest, enable Internet settings to use the WebAPI
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
Be sure to add
/>
to the end both statements -
Build it!
theta4j Part 2: use theta4j to take a picture
-
Under MainActivity, add
final Theta theta = Theta.createForPlugin();
-
Create a single threaded executor
-
private ExecutorService executor = Executors.newSingleThreadExecutor();
-
Suggest change the variable
i
in onKeyDown method to something more readable likekeyCode
, but this is not required -
Use executor.submit to run code when the key is pressed
if (keyCode == KeyReceiver.KEYCODE_CAMERA){ executor.submit(() -> {
-
Add theta.takePicture();
-
This will require you to add a try and catch statement
- Click on takePicture
- Move mouse to the left, light bulb will give option to add Try and Catch
-
Can add a
while
loop hereif (keyCode == KeyReceiver.KEYCODE_CAMERA){ // notificationLed3Show(LedColor.MAGENTA); notificationLedBlink(LedTarget.LED3,LedColor.MAGENTA,500); executor.submit(() -> { try { while (pictNumber < maxPicture){ theta.takePicture(); Thread.sleep(4000); pictNumber = pictNumber + 1; } notificationLedHide(LedTarget.LED3); notificationLed3Show(LedColor.MAGENTA);
Congratulations! You have built a fully functional THETA plug-in from scratch! Now that you’re at this point, you can add quite a bit of functionality and create plug-ins that take more advantage of many of the THETAs cool and interesting functionality.
So, create your own plug-in and submit it to the Plug-in Store. You can do it today!
Full Code
Finished apk: prettypicture/release at master · jcasman/prettypicture · GitHub
GitHub repo: GitHub - jcasman/prettypicture: Picture taking THETA plug-in with customized UI using LED colors and blinking
package guide.theta360.prettypicture;
import android.os.Bundle;
import android.view.KeyEvent;
// import com.theta360.prettypicture.R;
import com.theta360.pluginlibrary.activity.PluginActivity;
import com.theta360.pluginlibrary.callback.KeyCallback;
import com.theta360.pluginlibrary.receiver.KeyReceiver;
import com.theta360.pluginlibrary.values.LedColor;
import com.theta360.pluginlibrary.values.LedTarget;
import org.theta4j.webapi.Theta;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends PluginActivity {
private Theta theta = Theta.createForPlugin();
private ExecutorService executor = Executors.newSingleThreadExecutor();
private int pictNumber = 0;
private int maxPicture = 4;
private KeyCallback keyCallback = new KeyCallback() {
@Override
public void onKeyDown(int keyCode, KeyEvent keyEvent) {
if (keyCode == KeyReceiver.KEYCODE_CAMERA){
// notificationLed3Show(LedColor.MAGENTA);
notificationLedBlink(LedTarget.LED3,LedColor.MAGENTA,500);
executor.submit(() -> {
try {
while (pictNumber < maxPicture){
theta.takePicture();
Thread.sleep(4000);
pictNumber = pictNumber + 1;
}
notificationLedHide(LedTarget.LED3);
notificationLed3Show(LedColor.MAGENTA);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
@Override
public void onKeyUp(int keyCode, KeyEvent keyEvent) {
}
@Override
public void onKeyLongPress(int keyCode, KeyEvent keyEvent) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAutoClose(true);
notificationLed3Show(LedColor.MAGENTA);
}
@Override
protected void onResume() {
super.onResume();
setKeyCallback(keyCallback);
}
}