ProcessingでLiveWallpaperを作る

# はじめに
この記事はAndroidのLiveWallpaperについての記事です。
対象は以下のような人になります。

* android開発はしているけど、Processingはあまり触ったことがない。
* android開発はしているけど、LiveWallpaperはあまり触ったことがない。

# LiveWallpaperとは
Android2.1から使える、「動く壁紙」です。
ユーザーのタッチしている座標、加速度センサー、GPSなどの端末の情報を使うこともでき、見た目に楽しい壁紙にすることができます。
例えば、Pixel3の標準壁紙にも、画面のタッチに反応して動くLiveWallpaperなど、いくつかのLiveWallpaperが含まれています。
![videotogif_2018.12.22_19.38.48.gif](https://qiita-image-store.s3.amazonaws.com/0/20276/49028ee0-9782-4c8a-16d5-d8a7aa12e5e1.gif)

# Processingとは
電子アートとビジュアルデザインのためのプログラミング言語であり、統合開発環境である。アーティストによるコンテンツ制作作業のために、詳細な設定を行う関数を排除している。 視覚的なフィードバックが即座に得られるため、初心者がプログラミングを学習するのに適しており、電子スケッチブックの基盤としても利用できる。Java を単純化し、グラフィック機能に特化した言語といえる。
(Wikipediaより)
公式サイト : https://processing.org/

# LiveWallpaper with Processing
ProcessingのAndroid Modeを使うことで、Processingで書いたコードをAndroidアプリとして出力することができます。
2017/9リリースのAndroid Modeバージョン4.0でLiveWallpaper、Watch Face、VRがサポートされ、Processingで書いたコードを直接LiveWallpaper、Watch Face、VRアプリとして出力することができるようになりました。ただし、以下の条件があります。

* LiveWallpaper : Android4.2以上
* Watch Face : Android Wear2.0(Wear OS by Google 1.0)以上
* VR : Android4.4以上

LiveWallpaperやWatchFaceなどのビジュアルデザインが主な要素となるアプリにおいて、Processingはとても相性が良いのではないかと思います。

# 簡単なLiveWallpaperアプリを作る
## Android Modeの追加
![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/e82e6ac4-fa7d-64e4-618b-57f5d11b4844.png)
初めはJavaモードしか使えないので、Android Modeを追加します。
PDE(開発環境)右上のJavaと書いてあるところから、「モードの追加」を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/69ee2f19-ff62-def7-aa9f-b9ce36ac4f31.png)
モード管理画面が開くので、「Android Mode」を選択し、インストールします。

## スケッチの作成
```Java:wallpaper01.pde
void setup() {
  strokeWeight(12);
}

void draw() {
  background(204);

  // White line
  stroke(255);
  line(width/2, height/2, mouseX, mouseY);

  // Black line
  stroke(0);
  float mx = map(mouseX, 0, width, width*3/4, width/4);
  float my = map(mouseY, 0, height, height*3/4, height/4);
  line(width/2, height/2, mx, my);
}
```
Processingで書かれたプログラムはスケッチと呼ばれます。
白い線を画面中心からタッチしている位置に引き、黒い線を白い線の半分の長さで反対方向に引く。
というコードです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/d21717a8-af27-6c59-743d-4f8bb5747644.png)
普通にJavaモードで実行するとこんな感じです。

## LiveWallpaperアプリとして出力する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/01fd30d2-9cd5-34e6-6125-26c2f91df3d6.png)
Androidモードに変更します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/c88910df-78a7-e971-1966-33b0bdbeba9e.png)
ProcessingのメニューにAndroidが表示されるので、「Wallpaper」を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/860f6758-dc2c-cda6-b0f4-bb20a94e96ab.png)
端末をPCに接続するとDevicesに接続している端末が出ているはずです。

この状態で実行すると、接続しているAndroid端末にLiveWallpaperアプリがインストールされ、壁紙の変更から作成したLiveWallpaperを使うことができます。

![videotogif_2018.12.22_21.37.08.gif](https://qiita-image-store.s3.amazonaws.com/0/20276/339f2b80-d0c1-8ccc-c98a-4f91559d9de0.gif)

# センサー情報を取得する
通常のAndroidでの取得方法と同じです。
下記は、最新の加速度センサーの情報をテキスト表示する例です。

```Java 
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

Context context;
SensorManager manager;
Sensor sensor;
AccelerometerListener listener;
float ax, ay, az;

void setup() {
  fullScreen();
  
  context = getContext();
  manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
  sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  listener = new AccelerometerListener();
  manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);

  textFont(createFont("SansSerif", 30 * displayDensity));
}

void draw() {
  background(0);
  text("X: " + ax + "\nY: " + ay + "\nZ: " + az, 0, height/3, width, height);
}

class AccelerometerListener implements SensorEventListener {
  public void onSensorChanged(SensorEvent event) {
    ax = event.values[0];
    ay = event.values[1];
    az = event.values[2];    
  }
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
  }
}
```
https://android.processing.org/tutorials/sensors/index.html

端末を傾けると表示が変化します。
![videotogif_2018.12.23_14.31.01.gif](https://qiita-image-store.s3.amazonaws.com/0/20276/eb13f55e-f73b-127b-2694-a11810a9b73d.gif)


# Ketaiライブラリを使って端末情報を取得する
センサー情報や位置情報などのAndroid端末からの情報をProcessingコードから簡単に取得できるライブラリとして、Ketaiがあります。端末からの情報取得部分をラップしてくれています。
http://ketai.org/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/1096058e-5069-0ec2-d9cd-73d99cdaacb8.png)
メニュー > スケッチ > ライブラリをインポート > ライブラリを追加、からライブラリの追加ができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20276/8816f31a-9f64-3401-f9ce-a69140c61aee.png)
Ketaiを選択し、インストールします。

<img width="400" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/20276/46e0da0e-eb82-e067-c6c7-50d8f5ba88ed.png">
ライブラリをインポートからKetaiを選択すると、import文がスケッチに追加されます。
(必要のないものまで追加されてしまうので、手で書いたほうが良いかもしれません)

KetaiSensorクラスを使うと、先程の最新の加速度センサーの情報を表示する例は、以下のようなコードになります。

```Java
import ketai.sensors.*;

KetaiSensor sensor;
float ax, ay, az;

void setup() {
  fullScreen();
  
  sensor = new KetaiSensor(this);
  sensor.start();
  
  textFont(createFont("SansSerif", 30 * displayDensity));
}

void draw() {
  background(0);
  text("Ketai-X: " + ax + "\nKetai-Y: " + ay + "\nKetai-Z: " + az, 0, height/3, width, height);
}

void onAccelerometerEvent(float x, float y, float z){
  ax = x;
  ay = y;
  az = z;
}
```

その他にも、カメラやNFC、Wifiを使うこともできるようです。
以下にチュートリアルがあります。
http://ketai.org/tutorials/

# パーミッションの取得
位置情報の取得など、端末の情報取得にパーミッションが必要な場合があります。
例えば、以下はKetaiを使って位置情報を取得し画面に表示するコードですが、初期状態で動かしてもパーミッションがないため位置情報を取得することできません。

```Java
import ketai.sensors.*; 

double longitude, latitude, altitude;
KetaiLocation location;

void setup() {
  fullScreen();
  location = new KetaiLocation(this);

  textAlign(CENTER, CENTER);
  textSize(displayDensity * 36);
}

void draw() {
  background(78, 93, 75);
  if (location == null  || location.getProvider() == "none") {
    text("Location data is unavailable. \n" +
      "Please check your location settings.", 0, 0, width, height);
  } else {
    text("Latitude: " + latitude + "\n" + 
      "Longitude: " + longitude + "\n" + 
      "Altitude: " + altitude + "\n" + 
      "Provider: " + location.getProvider(), 0, 0, width, height);
  }
}

void onLocationEvent(double lat, double lon, double alt) {
  longitude = lon;
  latitude = lat;
  altitude = alt;
}
```

<img width="300" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/20276/3021387e-1c17-6c29-17f9-dc9660de393d.png">
<img width="300" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/20276/eba131ac-2e65-ec66-2e46-289327a18d2c.png">
メニュー　> Android > Sketch Permissionsを選択し、必要なパーミッションにチェックを付けて実行することで、パーミッションの確認をすることができます。

<img width="300" alt="wallpaper01.png" src="https://qiita-image-store.s3.amazonaws.com/0/20276/a11fb69c-a49d-0b08-c21c-4ae0361c5b77.png">
付与したパーミッションは、壁紙選択時に確認され、許可をしてもらう事で情報を取得することができます。

# アプリの署名と配布
<img width="300" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/20276/a8325eb8-8c16-8de8-bd8f-920699e3f330.png">
「Export Signed Package」というメニューがありますが、普段Android開発をしている方であれば、「Export Android Project」で作成したスケッチをAndroidプロジェクトとして出力し、通常通りbuild.gradleにsigning configを指定するのがわかりやすいかと思います。

# Android StudioでのProcessing開発
上記で示したように、Processingで書いたスケッチはAndroidプロジェクトに変換され実行されます。PDE(Processingの統合開発環境)は補完が効かないなど使いにくいところが多いので、AndroidStudioで開発すると効率的にコードが書けます。また、Kotlinで書けることもメリットかと思います。

## Android用のProcessingライブラリを追加
```groovy
implementation 'org.p5android:processing-core:4.0.3'
```
org.p5android:processing-coreを依存関係に追加します。

## 描画部分のクラス作成
```Kotlin
class Wallpaper01 : PApplet() {

    private var longitude: Double = 0.0
    private var latitude: Double = 0.0
    private var altitude: Double = 0.0
    private var location: KetaiLocation? = null

    override fun setup() {
        location = KetaiLocation(this)

        textAlign(PConstants.CENTER, PConstants.CENTER)
        textSize(displayDensity * 36)
    }

    override fun draw() {
        background(78f, 93f, 75f)
        if (location == null || location!!.provider === "none") {
            text("Location data is unavailable. \n" + "Please check your location settings.", 0f, 0f, width.toFloat(), height.toFloat())
        } else {
            text("Latitude: " + latitude + "\n" +
                    "Longitude: " + longitude + "\n" +
                    "Altitude: " + altitude + "\n" +
                    "Provider: " + location!!.provider, 0f, 0f, width.toFloat(), height.toFloat())
        }
    }
```
PAppletを継承したクラスを作ります。PAppletにProcessingで使えるメソッドが定義してあるため、あとはProcessingで書いていたのと同じようにコードを書いていくだけです。

## LiveWallpaper用のクラス作成
```Kotlin
class MainService : PWallpaper() {
    override fun createSketch(): PApplet {
        return Wallpaper01()
    }
}
```
LiveWallpaperを作る場合は、PWallpaperを継承したServiceを作成し、createSketchメソッドをオーバーライドして、先程作ったPApplet継承クラスのインスタンスを生成して返せば完了です。

# まとめ
Processingを使ったLiveWallpaperアプリの作成を紹介しました。
綺麗な壁紙や面白い壁紙を作れるようにがんばります。

# 参考
https://android.processing.org/
http://ketai.org/
https://gist.github.com/beesandbombs