RICOH THETA Z1の有機ELパネルをプラグインからコントロールする方法

## RICOH THETA Z1がついに日本でも発売

リコーの@ueueです｡

[THETA Z1](https://thetaz1.com/ja/)が日本でも発売になりました｡  

![z1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/cc5201bf-c6a3-84aa-f67e-e30b5c1e553c.png)


THETA Z1もVと同じくプラグインをインストールして機能を拡張することができます｡
最高かよ｡

そして､THETA Z1には有機ELパネル(OLED)がついています｡
神だな､おい｡
![oled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/192e4a58-a1d4-fece-0d96-8dda47c37508.png)

ということで､この記事ではプラグインからOLEDの表示をコントロールする方法について説明します｡
ちなみに[THETAプラグイン開発者向けドキュメント](https://api.ricoh/docs/theta-plugin-reference/broadcast-intent/)の｢Control OLED｣の章に同じことが記載されているので､英語つよつよの人はそちらを参照いただければと思います｡



THETA プラグイン is 何？という方は[こちら](https://qiita.com/mrtakada/items/8f3bbf8d283c26899473)

## 本題

先にも記載しましたが､THETA Z1は撮影情報を表示するモノクロのOLEDを搭載しています｡大きさは128×36ピクセルです｡  
このOLEDの下2/3の領域(128×24)に対してプラグインから文字列または画像を表示させることが可能です｡逆にプラグインモードのときでも､OLEDの表示を通常モードと同じようにすることも可能です｡また､｢何も表示させない｣といった制御も可能です｡
画面の明るさも制御可能で､1-100の間で指定できます｡

この記事では｢各ボタンで表示を切り替えるプラグイン｣のサンプルコードを元にして
OLEDの表示をコントロールする方法について解説します｡

サンプルプログラムのボタンと表示内容の対応は以下のとおりです｡

 * シャッターボタンで文字列を表示
 * シャッターボタン長押しで何も表示させない
 * Wi-Fiボタンで画像を表示
 * Wi-Fiボタン長押しで画像を点滅表示
 * ファンクションボタン(Fn)で通常モードの画面表示

また､画面の明るさは100としています｡

サンプルコードは以下のとおりです｡

```java
public class MainActivity extends PluginActivity {
    private Bitmap theta_bmp = null;

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

        // 画像の準備
        try (InputStream inputStream = getAssets().open("theta.bmp")) {
            theta_bmp = BitmapFactory.decodeStream(inputStream);
        } catch (IOException e) {
            notificationError("Failed to load theta.bmp");
        }

        //明るさの調整
        Intent oledBrightnessIntent = new Intent("com.theta360.plugin.ACTION_LED_BRIGHTNESS_SET");
        oledBrightnessIntent.putExtra("target", "OLED");
        oledBrightnessIntent.putExtra("brightness", 100);
        sendBroadcast(oledBrightnessIntent);

        setKeyCallback(new KeyCallback() {
            @Override
            public void onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
                    Intent textIntent = new Intent("com.theta360.plugin.ACTION_OLED_TEXT_SHOW");
                    textIntent.putExtra("text-middle", "hogehoge");
                    textIntent.putExtra("text-bottom", "fugafufa");
                    sendBroadcast(textIntent);
                } else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {
                    Intent imageIntent = new Intent("com.theta360.plugin.ACTION_OLED_IMAGE_SHOW");
                    imageIntent.putExtra("bitmap", theta_bmp);
                    sendBroadcast(imageIntent);
                } else if (keyCode == 119) {  // 119はFnボタンのKeyCode
                    Intent oledSetIntent = new Intent("com.theta360.plugin.ACTION_OLED_DISPLAY_SET");
                    oledSetIntent.putExtra("display", "basic");
                    sendBroadcast(oledSetIntent);
                }
            }

            @Override
            public void onKeyLongPress(int keyCode, KeyEvent event) {
                if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
                    Intent textIntent = new Intent("com.theta360.plugin.ACTION_OLED_HIDE");
                    sendBroadcast(textIntent);
                } else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {
                    Intent blinkImageIntent = new Intent("com.theta360.plugin.ACTION_OLED_IMAGE_BLINK");
                    blinkImageIntent.putExtra("bitmap", theta_bmp);
                    blinkImageIntent.putExtra("period", 300);
                    sendBroadcast(blinkImageIntent);
                }
            }

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

※ 現時点(2019/05/22)ではプラグインSDKにOLED表示のためのメソッドは存在しないので､インテントを直接利用するコードになっています｡

## 文字列表示
OLEDの下2/3の領域に2行の文字列を個別に表示させることが可能です｡
サンプルコードの以下の部分が文字列表示に対応します｡

```java
if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
         Intent textIntent = new Intent("com.theta360.plugin.ACTION_OLED_TEXT_SHOW");
         textIntent.putExtra("text-middle", "hogehoge"); // 真ん中の領域に表示される文字列
         textIntent.putExtra("text-bottom", "fugafufa"); //一番下の領域に表示される文字列
         sendBroadcast(textIntent);
```
表示は以下のようになります｡
![moji.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/926107b6-2b6a-f929-fa99-378cf27f44a2.jpeg)

IntentクラスのputExtraメソッドで文字列を設定します｡text-middleが画面を3分割した真ん中の行に表示されます｡text-bottomが画面が一番下の行です｡

表示できるのはASCII printable charactersの大文字です｡サンプルコードのように指定した文字列に小文字が使われている場合は､自動的に大文字に変換されます｡

以下にその他の注意事項をまとめます｡

* text-middleを指定しない場合はプラグイン名が表示されます｡
* text-bottomを指定しない場合は空白が表示されます
* 表示は左詰めになります｡
* 表示領域から指定した文字列がはみ出る場合には、スクロールしてすべての文字が表示されます｡スクロールをプラグインから制御することはできません。
  
以下が､スクロールさせた場合の画像です｡1行目は"KAOMOJI"という短い文字列｡2行目に顔文字が続く長い文字列を設定しました｡2行目のほうだけスクロールが走ります｡

![OLED_Scroll_w640.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/0398bebf-760e-b3cc-7dc2-ab765a480470.gif)
 
## 画像表示
次に画像表示ついて説明します｡
画像はOLEDの下2/3の領域に一つの画像を表示させることができます｡
また､点滅表示をさせることも可能です｡

### 画像の準備
まずは画像を準備します｡

画像の形式はビットマップ､大きさは128x24にする必要があります｡
形式や大きさが異なると何も表示されませんのでご注意ください｡

今回はサンプル画像として､いらすとやの360度カメラを表示させてみました｡
![camera360.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/31fb9625-a95f-cb89-b2a5-a6028a2f7a47.png)
大きさが128x40のなるように画像を修正してビットマップとして保存します｡

この画像ファイルをアセットフォルダーに配置します｡
アセットフォルダーは､Android Studioのメニューから
[File] -> [New] -> [Folder] -> [Assets Folder]
で作成できます｡

なお､カラー画像であってもTHETA側でモノクロに変換して表示するので､濃淡を気にしないならばカラーのビットマップファイルをアセットフォルダーに配置するだけでオッケーです｡

画像そのものの作り方については最後の｢おまけ｣でもう少し細かく説明します｡

### サンプルコード(Assetsから画像を取り込む)

まずアセットフォルダ内の画像を取り込む部分が以下になります｡

```java
// 画像の準備
try (InputStream inputStream = getAssets().open("theta.bmp")) {
    theta_bmp = BitmapFactory.decodeStream(inputStream);
} catch (IOException e) {
    notificationError("Failed to load theta.bmp");
}

```


### サンプルコード(画像の表示)
Wi-Fiボタンを押して画面に表示させる部分が以下になります｡
“com.theta360.plugin.ACTION_OLED_IMAGE_SHOW” インテントを利用します｡

```java
} else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {
    Intent imageIntent = new Intent("com.theta360.plugin.ACTION_OLED_IMAGE_SHOW");
    imageIntent.putExtra("bitmap", theta_image);
    sendBroadcast(imageIntent);
```

表示は以下のようになります｡
![oled_theta.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/f24879d7-6dff-da33-2dac-4b37f6ea86a1.jpeg)


### サンプルコード(画像の点滅表示)
画像を点滅させたい場合は “com.theta360.plugin.ACTION_OLED_IMAGE_BLINK”インテントを利用します｡

putExtraメソッドのkeyとして"period"指定して､点滅間隔を制御できます｡
制御間隔1-2000[msec]の間で指定できます｡デフォルトは2000 [msec]です｡

対応するサンプルコードは以下の箇所です｡ここでは間隔を300msecに設定しています｡

```java
else if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {
    Intent blinkImageIntent = new Intent("com.theta360.plugin.ACTION_OLED_IMAGE_BLINK");
    blinkImageIntent.putExtra("bitmap", theta_image);
    blinkImageIntent.putExtra("period", 300);
    sendBroadcast(blinkImageIntent);
}
```

## 通常モードと同じ表示にする

OLEDの表示を通常のモードとする場合には
“com.theta 360.plugin.ACTION_OLED_DISPLAY_SET”インテントを利用して
putExtraメソッドのkeyを"display"､値を"basic"とします｡

サンプルコードの以下の部分が対応します｡

```java
else if (keyCode == 119) {  //ファンクションボタン
    Intent oledIntentSet = new Intent("com.theta360.plugin.ACTION_OLED_DISPLAY_SET");
    oledIntentSet.putExtra("display", "basic");
    sendBroadcast(oledIntentSet);
```

なお､Z1で追加されたファンクションボタンについてはKey Codeの定数が定義されていないので､[こちらのドキュメント](https://api.ricoh/docs/theta-plugin-reference/broadcast-intent/)を参考に値を119としました｡

![keycode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/4aa9f5a2-3964-2263-96b1-5717298fe03a.png)

表示は以下のようになります｡
![normal_mode.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/0bb70c9b-1a80-0efc-8201-55a2c233ed20.jpeg)

## 何も表示させない
プラグインで制御できる下2/3領域にに何も表示させたくない場合は
“com.theta360.plugin.ACTION_OLED_HIDE”インテントを利用します｡

```java
if (keyCode == KeyReceiver.KEYCODE_CAMERA) {
    Intent textIntent = new Intent("com.theta360.plugin.ACTION_OLED_HIDE");
    sendBroadcast(textIntent);
```

表示は以下のようになります｡
![oled_nothing.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/1ae49daa-db73-3873-b360-3c3c460192ca.jpeg)


## 画面の明るさ
画面の明るさは以下の部分で設定しています｡

```java
//明るさの調整
Intent oledBrightnessIntent = new Intent("com.theta360.plugin.ACTION_LED_BRIGHTNESS_SET");
oledBrightnessIntent.putExtra("target", "OLED");
oledBrightnessIntent.putExtra("brightness", 100);
sendBroadcast(oledBrightnessIntent);
```
インテントの値が
com.theta360.plugin.ACTION_"O"LED_BRIGHTNESS_SET
ではなく
com.theta360.plugin.ACTION_LED_BRIGHTNESS_SET
であることにご注意ください｡

このインテントはOLEDだけでなく､他のLEDの明るさ調整にもつかわれるため"OLED"ではなく"LED"になっています｡したがって､putExtraメソッドのtargetの値を “LED1”､ “LED2”とすることでLEDの明るさコントロールにも利用できます｡

## おまけ(画像の作成について)

最後に表示させる画像についていくつかTipsを紹介します｡

### 濃淡のコントロール
以下が､新宿の街で信号を見上げるワイです｡
![uesan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/861d6217-088a-1529-84b6-4c79a7e0df09.png)

このようにごちゃごちゃしたカラー画像をTHETA側のおまかせでモノクロに変換すると､なんだかよくわからない画像になります｡

![oled_uesan.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/70040b62-2b1b-cdf3-1219-2064b264f5d3.jpeg)

このような場合､例えば[このサイト](https://www.peko-step.com/tool/grayscale.html)などで､自分でしきい値を調整しながらモノクロ画像をつくることで見やすく改善することが可能です｡
上記サイトで調整しながらモノクロに変換したのが､次の画像です｡

![uesan_mono.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/852b41ff-0b2e-fba4-65e4-d41170468b8f.png)
これをTHETAで描画すると
![oled_uesan_mono.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/c72e48cb-ba33-704e-66f1-ad2a087cdade.jpeg)

けっこうよくなったのが伝わるでしょうか｡

### ビットマップ画像を自分で作成

これまでのサンプルはすでにできあがった画像を表示していましたが､自分で画像を作成することも可能です｡
詳しくないので､横シマを描画する簡単なサンプルだけのせておきます｡

```java
int black = 0xFF000000;
int white = 0xFFFFFFFF;
Bitmap bitmap2 = Bitmap.createBitmap(128, 24, Bitmap.Config.ARGB_8888 );
for (int width=0; width<128; width++) {
    for (int height=0; height<24; height++) {
        //if (width%2==0) { //縦縞
        if (height%2==0) {  //横縞
            bitmap2.setPixel(width, height, white);
        } else {
            bitmap2.setPixel(width, height, black);
        }
    }
}
```

こんな感じで横縞が描画されます
![横縞.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/4890f9df-e440-d04c-cfe5-7ba370d04570.jpeg)


コードのコメント行のところを下記のように入れ替えて､縦縞を有効にすると

```java
if (width%2==0) { //縦縞
// if (height%2==0) {  //横縞
```

縦縞が描画されます｡
![縦縞.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264025/b81dc6d2-6023-0764-fe3b-9238500e15c8.jpeg)

興味を持った方は[このあたり](https://developer.android.com/reference/android/graphics/Bitmap.Config.html#ARGB_8888)を読めばもっといろいろできると思います｡

あと､近々､[THETAプラグイン開発者コミュニティ](https://qiita.com/organizations/theta-plugin)のメンバーがOLEDの画像描画についてもうすこしつっこんだ記事を書くっぽいです｡

## まとめ
THETA Z1の有機ELパネルの表示をプラグインからコントロールする方法を説明しました｡

## RICOH THETAプラグインパートナープログラムについて
THETAプラグインに興味を持たれた方がいれば、以下の記事もぜひご覧ください。

 * [THETAプラグインパートナープログラムはじめました](https://qiita.com/mrtakada/items/8f3bbf8d283c26899473)
 * [【THETAプラグイン開発】プラグインパートナープログラムに登録してみよう](https://qiita.com/mShiiina/items/55d98f366e650ca42251)

[RICOH THETAプラグイン開発者コミュニティ](https://qiita.com/organizations/theta-plugin)では、他にも記事を書いています。
RICOH THETAプラグインについては[こちら](https://api.ricoh/products/theta-plugin/)に情報がまとまっています。興味を持たれた方は[twitter](https://twitter.com/thetaplugin)のフォローと[THETAプラグイン開発コミュニティ(slack)](https://join.slack.com/t/thetadeveloper/shared_invite/enQtNzcxODI2MTk2ODg0LWY5YmU2ZTIxNGYwNzlmNWZjMWMyMWFlMzY3ZmQ3NGU3ZjZiZjI0Njk4MGIxMDU5NDJiMzQ4Y2FkNDEzYmFlNGU)への参加もぜひどうぞ｡