RICOH Blog Post: “THETA Plug-in Development - Building ‘Hello, World’ with a THETA plug-in”

This article is translated by @jcasman from the original here. The author is (@meronpan).


INTRODUCTION

Hello, this is @meronpan (because I love the Japanese melon shaped bread called “meronpan”) from Ricoh. 1f348 This is a “Hello, World” type introduction about THETA V plug-in development using the SDK.

Here is how to install the SDK.

We are going to make THETA sparkle!

If you are not familiar with THETA plug-ins, please read this article.

Although it’s called a plug-in, it’s the same as developing an Android app. That said, the points below are different from a normal Android smartphone, so some adjustments are necessary.

  • 360 degrees photosphere camera (2 cameras work simultaneously)
  • No screen
  • Unique buttons and LEDs
  • 4-channel microphone included

Due to these differences, there are extra differences mainly in the camera and audio sections of the API. pluginlibrary is included in the SKD. This will basically be used as-is without change, and the rest will be altered.

TABLE OF CONTENTS

The following points concerning THETA V plug-ins will be explained:

  • Basic use of THETA’s buttons
  • Basic use of LEDs
  • Creating a plug-in to change the colors of the wireless LED
  • Tweets by meronpan

BASIC USE OF THETA’S BUTTONS

I will go over the basics and usage of buttons.

LEARN THE BASICS OF BUTTONS

There are 2 points to remember in using buttons:

  • Button types
  • Button operation types

Please check before using.

BUTTON TYPES
Below are button types. Let’s confirm the key code constant which corresponds to them.

Number Button Keycode
4 Shutter Button KeyReceiver.KEYCODE_CAMERA
12 Wi-Fi Button KeyReceiver.KEYCODE_WLAN_ON_OFF
13 Mode Button KeyReceiver.KEYCODE_MEDIA_RECORD

BUTTON OPERATION TYPES
For button operation, the callback functions below are available.

Button Operation Callback Function
Press button onKeyDown
Release button onKeyUp
Long press of Mode Button onKeyLongPress

HOW TO USE BUTTONS

The concept is you are going to combine button information introduced in the Basics of Buttons section and button operation types.

Let’s see how to use it with the SDK.

When using the SDK, MainActivity is the first to be called, but I’m going to focus in on the explanation of buttons here and just show part of what happens. Please enjoy some melon shaped bread as you watch.

1f348

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

onCreate will be called up at the very beginning just once, when MainActivity is run.

    @Override
    public void onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
            /*
             * To take a static picture, use the takePicture method.
             * You can receive a fileUrl of the static picture in the callback.
             */
            new TakePictureTask(mTakePictureTaskCallback).execute();
        }
    }

onKeyDown will be run when the button is pushed. In the middle, it’s spilt so that if the KEYCODE_CAMERA button is pressed, when the shutter button is pressed new TakePictureTask will be run.

    @Override
    public void onKeyUp(int keyCode, KeyEvent event) {
        /**
         * You can control the LED of the camera.
         * It is possible to change the way of lighting, the cycle of blinking, the color of light emission.
         * Light emitting color can be changed only LED3.
         */
        notificationLedBlink(LedTarget.LED3, LedColor.BLUE, 1000);
    }

    @Override
    public void onKeyLongPress(int keyCode, KeyEvent event) {
        notificationError("");
    }

Similarly, onKeyUp is run when the button is released, and onKeyLongPress is run when the button is pushed for a long time. Unlike onKeyDown where there is a choice, pressing any button will run it.

BASIC USE OF LEDs

I will go over the basic use of LEDs.

Please remember these 3 points:

  • 3 types of control—On, Off, Flashing
  • Can control LED3 through LED8 for the below list
  • LED3’s LED color can be changed
No. LED LED No
6 Wi-Fi LED LED3
7 Shooting Mode LED (Camera)LED4, (Video)LED5, (Live)LED6
8 Video Recording LED LED7
9 Memory Warning LED LED8

Let’s see how to use it with the SDK. Here’s the SKD.

In pluginlibrary, the functions below are available for controlling LEDs.

Specify a color and switch LED3 on.

public void notificationLed3Show(@NonNull LedColor ledColor)

Select LED3 through LED8 and switch the LED on.

public void notificationLedShow(@NonNull LedTarget ledTarget)

Flash the LED

public void notificationLedBlink(@NonNull LedTarget ledTarget, LedColor ledColor, int period)

Turn the LED off

public void notificationLedHide(@NonNull LedTarget ledTarget)

  • LedTarget - With enum, select one from LED3, LED4, …, LED8

  • LedColor - With enum, select one from RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, WHITE. Default is BLUE.

  • period - When using flash control, 1 cycle period (ms) is set between 250-2000. A number below 250 will be set at 250, and a number above 2000 will be set at 2000.

CREATING A PLUG-IN TO CHANGE THE COLORS OF THE WIRELESS LED
With what I have learned so far, I have made a plug-in that changes the wireless LED colors randomly and stops when the shutter button is pressed. Please see the video at the beginning of this article.

The 2 changes below will be added.

  • MainActivity
  • AndroidManifest.xml

CHANGING MainActivity

MainActivity was changed as shown below.

package com.theta360.pluginapplication;

import android.os.Bundle;
import android.view.KeyEvent;
import com.theta360.pluginapplication.task.TakePictureTask;
import com.theta360.pluginapplication.task.TakePictureTask.Callback;
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 java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends PluginActivity {

    //define schedule time interval
    private static final int TIMER_INTERVAL_PERIOD = 250;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //set timer so LED color will renew at certain time interval
        Timer timer = new Timer();

        Random ledColorRand = new Random();
        Random ledTargetRand = new Random();
        Random ledHideRand = new Random();

        //set run to perform every 250ms
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //select LED color randomly
                int ledColorNum = ledColorRand.nextInt(LedColor.values().length);
                //select turning on LED randomly
                int ledTargetNum = ledTargetRand.nextInt(LedTarget.values().length);
                //select turning off LED randomly
                int ledHideNum = ledHideRand.nextInt(LedTarget.values().length);

                //turn on LED3 with randomly selected color
                notificationLed3Show(LedColor.values()[ledColorNum]);
                //turn on randomly selected LED
                notificationLedShow(LedTarget.values()[ledTargetNum]);
                //turn off randomly selected LED
                notificationLedHide(LedTarget.values()[ledHideNum]);
            }
        }, 0, TIMER_INTERVAL_PERIOD);


        // Set a callback when a button operation event is acquired.
        setKeyCallback(new KeyCallback() {
            @Override
            public void onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
                    //by ending Timer, end randomly flashing color with certain interval
                    timer.cancel();
                    //turn off LED
                    notificationLedHide(LedTarget.LED3);
                    notificationLedHide(LedTarget.LED4);
                    notificationLedHide(LedTarget.LED5);
                    notificationLedHide(LedTarget.LED6);
                    notificationLedHide(LedTarget.LED7);
                    notificationLedHide(LedTarget.LED8);
                }
            }

            @Override
            public void onKeyUp(int keyCode, KeyEvent event) {
            }

            @Override
            public void onKeyLongPress(int keyCode, KeyEvent event) {
                //by ending Timer, end randomly flashing color with certain interval
                timer.cancel();
                //turn off LED
                notificationLedHide(LedTarget.LED3);
                notificationLedHide(LedTarget.LED4);
                notificationLedHide(LedTarget.LED5);
                notificationLedHide(LedTarget.LED6);
                notificationLedHide(LedTarget.LED7);
                notificationLedHide(LedTarget.LED8);
                //notification that plug-in has ended correctly
                notificationSuccess();
            }
        });
    }
}

Looking at the details…

//set run to perform every 250ms
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        //select LED color randomly
        int ledColorNum = ledColorRand.nextInt(LedColor.values().length);
        //select turning on LED randomly
        int ledTargetNum = ledTargetRand.nextInt(LedTarget.values().length);
        //select turning off LED randomly
        int ledHideNum = ledHideRand.nextInt(LedTarget.values().length);

        //turn on LED3 with randomly selected color
        notificationLed3Show(LedColor.values()[ledColorNum]);
        //select turning on LED randomly
        notificationLedShow(LedTarget.values()[ledTargetNum]);
        //select turning off LED randomly
        notificationLedHide(LedTarget.values()[ledHideNum]);
    }
}, 0, TIMER_INTERVAL_PERIOD);

timer.schedule will be called only once after running, because it was placed within onCreate. However, the run inside of onCreate will be called up periodically. With timer.schedule, run will be performed every 250ms.

    @Override
    public void onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
            //by ending Timer, end randomly flashing color with certain interval
            timer.cancel();
            //turn off LED
            notificationLedHide(LedTarget.LED3);
            notificationLedHide(LedTarget.LED4);
            notificationLedHide(LedTarget.LED5);
            notificationLedHide(LedTarget.LED6);
            notificationLedHide(LedTarget.LED7);
            notificationLedHide(LedTarget.LED8);
        }
    }

Originally, the code to take pictures with the camera was placed inside onKeyDown, but that part was rewritten to deal with turning off the LED. run, which had been periodically running with timer.cancel, is stopped. After that, updating the LED ends.

The last step is to turn the LED off by notificationLedHide.

        @Override
        public void onKeyLongPress(int keyCode, KeyEvent event) {
            //by ending Timer, end randomly flashing color with certain interval
            timer.cancel();
            //turn LED off
            notificationLedHide(LedTarget.LED3);
            notificationLedHide(LedTarget.LED4);
            notificationLedHide(LedTarget.LED5);
            notificationLedHide(LedTarget.LED6);
            notificationLedHide(LedTarget.LED7);
            notificationLedHide(LedTarget.LED8);
            //notification that plug-in has ended correctly
            notificationSuccess();
        }

onKeyLongPress is called up when the Mode Button is pressed for a long time.
Inside of onKeyLongPress, the process of ending the plug-in is performed.
timer.cancel and notificationLedHide have the same processing purpose as onKeyDown.
Finally, notificationSuccess is run to notify that the plug-in has ended correctly.

CHANGING AndroidManifest.xml

Because the THETA has no screen, the following change was made.

AndroidManifest.xml
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

In order to set the screen orientation, android:screenOrientation=“portrait” was added.
Without this code, when the THETA is tilted, it would be recognized that the screen has turned and onCreate would be run. As long as Android is running, when the screen is turned, the app is initialized.

TWEETS BY MERONPAN

How do you like a camera that can’t take a picture, but can sparkle with flashing LEDs? By using the code introduced here, I think it’s really fun to make an original plug-in that flashes LEDs, changing button types and button operation types.

I’m sure by now you are in love with THETA plug-ins!

If you are interested in THETA plug-in development, please register for the partner program!

Please be aware that the THETA with its serial number registered with the program will no longer be eligible for standard end-user support.

For detailed information regarding partner program please see here.

The registration form is here.

1 Like