Pepperアプリ3.0系開発時の「ちょっと困った」対応方法＋基礎知識まとめ

3.0系自分用忘備録です。適宜編集予定。
よく使うことのコピペ用・ど忘れした時用・最初から知ってたら便利だったなと思ったこと等。
PepperからAndroidStudio開発を始めた人向け情報に近いのかもしれないです。
比較的Android開発で使える技術は使える印象なので、書くこともそれほどないような気もしますが……。

#基礎
## ターミナルからのログ取得
adb connect （pepperのIPアドレス）
で接続後に
adb logcat -v time > log.txt
実行でLogcatの情報をPCに保存できる

■追記
adb logcat | grep (タグ名) > log.txt
のほうがアプリのログに絞って収集できるので良さそうです

## アプリケーションのサンプルが見たい
[SoftBank Robotics Labs](https://github.com/softbankrobotics-labs)
公式のサンプルアプリケーションが見れるので勉強になります。

## 公式のAPIリファレンスの場所
[API - QiSDK](https://qisdk.softbankrobotics.com/sdk/doc/pepper-sdk/ch4_api/api.html)
（完全に自分用リンク）

##お仕事かんたん生成3.0がどこかわからない
Pepper for Biz 3.0取扱説明書に載ってます。具体的にはここ。
[Pepper for Biz 3.0取扱説明書|Robot Suiteへのログイン](https://doc.robot.softbank.jp/pepper_biz_3/manual/index/topics_detail172/id=1687)
サポート情報 > Pepper for Biz 3.0 > Pepper for Biz 3.0取扱説明書 > Robot Suiteの利用の準備 > Robot Suiteへのログイン
Robot Suiteに到達したあとのお仕事作成方法はたぶん見ればわかるはず。はず……。

#AndroidStudio関連
##Pepper用アプリケーションの作成方法が分からない
SDKの導入方法などなどは[刻み目から点景](https://blog.happyhack.co.jp)さんの[Pepper SDK入門(1) Pepper SDKプラグインのインストール](https://blog.happyhack.co.jp/2019/02/pepper-sdk1-pepper-sdk.html)がお勉強になります。
SDKプラグイン導入後は同ブログの「はじめてのロボアプリ開発」から読んでいけば概ね分かるのではないかなと思います。

##File→New→RobotApplication...を選択したのに「extends RobotActivity implements RobotLifecycleCallbacks」記述周りでエラーが発生する
Syncが上手くいっていない可能性があります。
build.gradle(Module:app)ファイルを開いて、

```java:build.gradle(Module:app)
dependencies {
（省略）
    implementation 'com.aldebaran:qisdk:1.4.9'
    implementation 'com.aldebaran:qisdk-design:1.4.9'
}
```
この2行を一度切り取って再度貼り付けるなどをしたら表示される
「Gradle files have changed sinece last project syne.A project sync may be necessary for the IDE　to work properly.」の文字の横の「Sync Now」を押せば解決するはずです。

##Logを確認したい
Logcutで確認できます。

##メモリリークの確認をしたい
Profilerを利用します。（すごく使いにくい気がするのですが他に良い方法はあるのでしょうか……。）

##PepperのTabletの中身を確認したい
DeviceFileExplorerを使うとAndroidStudio上で確認できて便利です。

##ラムダ式をどうすれば使えるようにできるのかが分からない
コピペして引っ張ってきた`runOnUiThread(() ->{});`みたいなプログラムが使えなかったら「Alt＋Enter」キーを押して
![スクリーンショット 2019-09-05 10.19.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174363/02e796d9-7f53-7055-1614-bdb68f91e971.png)
「Set language level to 8 -Lambdas, type annotations etc.」を押すと解決します。

##デバッグ時、インストールからアプリの起動までがクソ重い件について
Pepper上でアプリを動かすにあたって必要なものだけbuildさせるようにすると軽くなります。
具体的には以下のここから〜ここまでの部分を追加。

```java:build.gradle
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        //（略）

        // ここから
        ndk {
            abiFilters "armeabi-v7a"
        }
        // ここまで
}
```



#開発関連
##Androidのディスプレイデザイン関連の作成方法が分からない
AndroidのSDK2.3系の本になるので情報が古いですが、「[Android Layout Cookbook アプリの価値を高める開発テクニック](https://www.amazon.co.jp/Android-Layout-Cookbook-アプリの価値を高める開発テクニック-あんざい/dp/4844329871)」に一通り触れてみると大分違うと思います。
本を買うのはちょっと……という場合は、「android.support.constraint.ConstraintLayout」ではなくて「LinearLayout」におけるデザインの組み方を調べて実装した方が手軽です。

##Permission設定関連
[少し親切なRuntime Permission対応](https://qiita.com/caad1229/items/35bab757217b204711df)さんがとても勉強になりました。

## アプリケーション内にファイルを同梱させる
[Android Studioで assets フォルダのテキストファイルを読み込む](http://androidstudio.hatenablog.com/entry/2014/07/24/173630)
jsonファイルやテキストファイルなどをアプリケーション内に同梱させたい際に使用しました。

##onDestroyでintentに記述を行っているのにお仕事再開時に想定通りの動作をしない
intentの書き込み→終了→お仕事再開時のintent読み取りの間で時間が足りない気配がするので終了まで少し時間を確保すると解決した気がします。

#2.5系からの移行関連
##html/CSS/jsを3.0系でも使い回したい
webviewを使う。JavaScriptとJava間連携の方法もAndroidでの実装方法を調べれば出てくるはず。
メモリやら色々が使えなくなってるのでhtmlやJavaScript詳しくないなら1から作った方ぜって早い人はたぶんいる。

##webviewに表示した2．5系のデザインがディスプレイ内に収まらない
Tapperを使って作ったデザイン、AndroidOSが8.0系のタブレットで表示してみるとうまくいくのにPepperと同じ7.0だと不具合が出るんですよね。adjust.jsがうまいこと動作しなくなっている気がします。
adjust.jsをコメントアウトした後、html上にあった
`<meta name="viewport" content="initial-scale = 1.335, minimum-scale = 1.335, maximum-scale = 1.335">`
この行を以下のように置換しました。
`<meta name="viewport" content="width=1280px, user-scalable=no, target-densitydpi=device-dpi">`
必ずしも解決するかは分かりませんが参考までに。3.0系のPepperのタブレットの型番やら諸々が変わった日がいつか来ると思うと胃が痛い。

##モーション移植
~~[Pepper SDK for Android Studio用アニメーションオブジェクトの生成](https://qiita.com/UMasaU/items/803b296c8bce7f056404)
天才。ありがとうございます。2.5系の膨大なソースから該当のモーションを探すよりも、モーションボックスをコピペして、該当のボックスのみを配置したbehaviorを仮作成したあとでソースを読むと手っ取り早かったです（ということに、もっと早く気づけば良かった）。~~
Android Studioのanimation editorから旧モーションのインポートができるようになったようです。
animation editorのウィンドウを開いて、[File]→[Import animation from XAR...]からいけます。


#Futureサンプル

#発話

```java:stringリソースを発話するやつ()
import com.aldebaran.qi.sdk.object.locale.Locale;
import static com.aldebaran.qi.sdk.object.locale.Language.JAPANESE;
import static com.aldebaran.qi.sdk.object.locale.Region.JAPAN;

    Locale locale = new Locale(JAPANESE, JAPAN);
    int resId = R.string.hogehoge;
    Future<Void> speech = SayBuilder.with(qiContext)
            .withText(qiContext.getString(resId))
            .withLocale(locale)
            .withBodyLanguageOption(BodyLanguageOption.DISABLED)
            .buildAsync()
            .andThenCompose(say -> say.async().run());
```
.withBodyLanguageOption(BodyLanguageOption.NEUTRAL)にすると旧animationSayと同じになります。

#モーション

```java:作ったモーションを動作させるやつ
    int animationId = R.raw.hogehoge;
    Future<Void> motion = AnimationBuilder.with(qiContext)
            .withResources(animationId).buildAsync()
            .andThenCompose(animation -> AnimateBuilder.with(qiContext)
                    .withAnimation(animation).buildAsync())
            .andThenCompose(animate -> animate.async().run());
```

#モーションと発話の合わせ技みたいなことをさせたい

```java:指定モーションのanimationSay的なサンプル
import com.aldebaran.qi.sdk.object.locale.Locale;
import static com.aldebaran.qi.sdk.object.locale.Language.JAPANESE;
import static com.aldebaran.qi.sdk.object.locale.Region.JAPAN;

    Locale locale = new Locale(JAPANESE, JAPAN);
    int resId = R.string.hogehoge;
    Future<Void> speech = SayBuilder.with(qiContext)
            .withText(qiContext.getString(resId))
            .withLocale(locale)
            .withBodyLanguageOption(BodyLanguageOption.DISABLED)
            .buildAsync()
            .andThenCompose(say -> say.async().run())
            .thenConsume(voidFuture -> {
                    if (voidFuture.getError() != null) {
                            Log.i(TAG, "エラー");
                    }});

    int animationId = R.raw.hogehoge;
    Future<Void> motion = AnimationBuilder.with(qiContext)
            .withResources(animationId).buildAsync()
            .andThenCompose(animation -> AnimateBuilder.with(qiContext)
                    .withAnimation(animation).buildAsync())
            .andThenCompose(animate -> animate.async().run())
            .thenConsume(voidFuture -> {
                    if (voidFuture.getError() != null) {
                            Log.i(TAG, "エラー");
                    }});

   Future<Void> futureBoth = Future.waitAll(speech, motion);

```
say、motionで各エラー掴んでおかないと数珠つなぎにしたときにエラーが起きて転けちゃうことがあったようななかったような……。

#聞き取り

```java:「はい」「いいえ」の公式聞き取りサンプルをベースにFuture化してみたやつ
    PhraseSet phraseSetYes = PhraseSetBuilder.with(qiContext)
            .withTexts("yes", "OK", "はい")
            .build();

    PhraseSet phraseSetNo = PhraseSetBuilder.with(qiContext)
            .withTexts("no", "Sorry","いいえ")
            .build();

    Future<Void> ｆuture = ListenBuilder.with(qiContext)
            .withPhraseSets(phraseSetYes, phraseSetNo)
            .buildAsync()
            .andThenCompose(listen -> listen.async().run())
            .andThenConsume(listenResult -> {
                String humanText = listenResult.getHeardPhrase().getText();
                Log.i(TAG, "listening:" + humanText);
                PhraseSet matchedPhraseSet = listenResult.getMatchedPhraseSet();
                if (PhraseSetUtil.equals(matchedPhraseSet, phraseSetYes)) {
                    String msg = "Heard phrase set: yes";
                    Log.i(TAG, msg);
                    }
                } else if (PhraseSetUtil.equals(matchedPhraseSet, phraseSetNo)) {
                    String msg = "Heard phrase set: no";
                    Log.i(TAG, msg);
                    }
                }
            });
```
モーションのやつみたいにまとめられるのかな……と思いつつやり方が分からないので詳しい方がいたら知りたいです。

#品質チェックリスト対応
##難読化について
[AndroidアプリのソースコードをProGuardで難読化](https://qiita.com/nori3tsu/items/c0512865342368e5d062)さんの手順で実行すれば大丈夫そうです。
が、proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txtなんて一文なくない……？と思った方（私です）は以下を参照のこと。
[Proguardを使ってAndroidアプリのコードを難読化する](https://www.itcowork.co.jp/blog/?p=3926)


#PepperとAndroidTablet間の移植関連
##Android TabletでPepperアプリを動作させる
Googleの審査に通るためとかではなく、雑にサンプルアプリを作成して動作させたい人向け。
RobotLifecycleCallbacksを消してonStart()から動作させてみたものの、Future周りとかで落ちる現象が発生した場合は以下の対処で動くようになります。
API4を用いてTablet側で作業を進めて最終的にPepperに戻すようにさせるならbuild.gradleのdefaultConfigにここから〜ここまで部分を突っ込んであげてください。
（Future周りのあれそれこれが関連しているようで、PepperのSDKをAPI7にしてminSdkVersionとかtargetSdkVersionとかを弄ればそっちでも大丈夫ですが、API4ベースで手間なくテスト動作させるならこの方法で充分だと思います）

```java:build.gradle
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        //（略）

        // ここから
        ndk {
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }
        // ここまで
}
```


#その他
##ロボアプリプロフェッショナル認定試験の対策と所感
リンク：[Pepperパートナープログラム認定資格](https://cbt-s.com/examinee/examination/s-robotics.html)
・アトリエ秋葉原で行われることもある「試験対策講座」に参加する
・「ロボアプリプロフェッショナル認定学習用ワークブック」を元に試験対策講座で聞いた箇所を覚える
・「Pepper 開発ワークショップ （Pepper SDK for Android）＠アトリエ秋葉原」の資料をDLし、パワーポイントと解説を読み込む
・「Pepper for Biz 3.0取扱説明書」と「Robot Suite取扱説明書」を読み込む
・「Robot Suite取扱説明書」の内容とは別に、お仕事かんたん生成3.0周りはアトリエ秋葉原に行って実機を触って覚えた方がいいです
・「ロボアプリ品質チェックリスト（NAOqi 2.9）」をざっくりと覚える
・「ロボアプリプロフェッショナル認定学習用ワークブック」の6章に出ているような「Say」とか「Animate」とか題目になっているもののSDKに記載されているコーディングを丸暗記しておく（何も見ないで手書きでコードを書けるくらい覚えたほうが絶対に良いです）（選択肢問題ですが、手書きで書けるレベルまでを自分の常識にしておかないと辛いです）
・上記内容をどの程度自分の中に常識として落とし込めるかのテストの印象。2.5時代より性格が悪い問題は少ないものの、「このくらいPepperで開発してるなら常識でしょ？」という要求レベルが底上げされているような気がしました（個人の意見です）。
・ところで地方のPepper開発担当者は対策講座の為に秋葉原に行くんです？要求がシビアでは？