Pepper SDK入門(17) Autonomous Abilities②

今回のチュートリアルでは、PepperのAutonomous Abilityの停止と解除の方法について見ていきます。

Futureを使いますので、Futureについて知りたい人は[Pepper SDK入門(8) アクションの連結](https://qiita.com/kskrin/items/d352a7a0bbb16bf17533)を参考にしてください。

###まずは新しいプロジェクトを作成する
AutonomousPepperという名前で新しいプロジェクトを作成します。
そして、QiSDKの設定とMainActivityを作成しロボットライフサイクルの実装を行ってください。

##1.Abilityを停止する
MainActivityのクラスに新しい<code>holdAbilities</code>メソッドを実装します。

```java

private void holdAbilities(QiContext qiContext) {
    // AbilityのためのHolderをビルドして保存
    Holder holder = HolderBuilder.with(qiContext)
            .withAutonomousAbilities(
                    //呼吸を模した待機時間の動き
                    AutonomousAbilitiesType.BACKGROUND_MOVEMENT,
                    //周辺の物質や人の検知
                    AutonomousAbilitiesType.BASIC_AWARENESS,
                    //目のLEDの点滅
                    AutonomousAbilitiesType.AUTONOMOUS_BLINKING
            )
            .build();

    // Abilityを非同期に停止
    Future<Void> holdFuture = holder.async().hold();
}
```
Abilityを停止するにはHolderBuilderでHolderをビルドする必要があります。
Holderに停止したいAbilityのAutonomousAbilitiesType (Enum) を渡してください。
続いて、非同期でAbilityを停止するためにHolderの<code>async</code>メソッドと<code>hold</code>メソッドを呼びます。
AutonomousAbilityを停止する方法を理解したところで、次はそれを解除できるようにする方法を見ていきましょう。

**プログラミングでよく使う書き方をデザインパターンといいます。Builderというのはよく出てくるデザインパターンなので、[ここ](https://qiita.com/i-tanaka730/items/10596f3c7a7a2df806e2)で軽く勉強しておいてください。**

##2.Abilityを解除する
ここでは、AutonomousAbilityの解除方法について見ていきます。
まずは新しく<code>releaseAbilities</code>メソッドを作成してください。

```java

private void releaseAbilities(Holder holder) {
    // Holderを非同期に解除
    Future<Void> releaseFuture = holder.async().release();
}
```

AutonomousAbilityを非同期で解除するために、対応するHolderインスタンスの<code>async</code>メソッドと<code>release</code>メソッドを呼びます。
続いて、機能の停止と解除をテストするための実装を行なっていきましょう。

##3.停止と解除の切り替えをテストする
Abilityの停止と解除を切り替えるためのボタンを作っていきます。

まずはレイアウトファイルのactivity_main.xmlに、下記を書き加えます。

```java

<Button
    android:id="@+id/button_switch_autonomous"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="Hold"/>
```

続いて、MainActivityに以下のフィールドを作成します。

```java

// button_switch_autonomousはAbilityの停止と解除の切り替えに使用
private Button buttonSwitchAutonomous;
// booleanはAbilityの状態を保存するのに使用
private boolean abilitiesHeld = false;
// AbilityのためのHolder
private Holder holder;
// QiSDKによるQiContext
private QiContext qiContext;
```

<code>onRobotFocusGained</code>メソッドと<code>onRobotFocusLost</code>メソッド用に以下のコードを書きます。

```java

@Override
public void onRobotFocusGained(QiContext qiContext) {
    // QiContextを保存
    this.qiContext = qiContext;
}

@Override
public void onRobotFocusLost() {
    // QiContextを外す
    this.qiContext = null;
}
```

<code>onCreate</code>メソッドのonClick listenerにbutton_switch_autonomousを設定します。

```java

// ビューの中のbutton_switch_autonomousを検索
buttonSwitchAutonomous = (Button) findViewById(R.id.button_switch_autonomous);

//buttonSwitchAutonomousをonClick listenerに設定
buttonSwitchAutonomous.setOnClickListener(v -> {
    // Activityのフォーカスをチェックする
    if (qiContext != null) {
        toggleAbilities();
    }
});
```
<code>toggleAbilities</code>メソッドを書き加えます。

```java
private void toggleAbilities() {
    // buttonSwitchAutonomousを利用できないようにする
    buttonSwitchAutonomous.setEnabled(false);

    if (abilitiesHeld) {
        releaseAbilities(holder);
    } else {
        holdAbilities(qiContext);
    }
}

```

<code>holdAbilities</code>メソッドを次のように更新します。

```java

// AbilityのHolderをビルドして保存
holder = HolderBuilder.with(qiContext)
                      .withAutonomousAbilities(
                              //呼吸を模した待機時間の動き
                              AutonomousAbilitiesType.BACKGROUND_MOVEMENT,
                              //周辺の物質や人の検知
                              AutonomousAbilitiesType.BASIC_AWARENESS,
                              //目のLEDの点滅
                              AutonomousAbilitiesType.AUTONOMOUS_BLINKING
                      )
                      .build();

// Abilityを非同期に停止
Future<Void> holdFuture = holder.async().hold();

// UIスレッド上のlambdaを停止
holdFuture.andThenConsume(Qi.onUiThread((Consumer<Void>) ignore -> {
    //Abilityの状態を保存
    abilitiesHeld = true;
    //buttonSwitchAutonomousのテキストを変更
    buttonSwitchAutonomous.setText("Release");
    //buttonSwitchAutonomousを利用できるようにする
    buttonSwitchAutonomous.setEnabled(true);
}));
```
<code>releaseAbilities</code>メソッドのreleaseFutureにFutureで繋いで、ボタン制御の処理をJavaの省略式であるlambdaで記述します。


```java

// UIスレッド上のlambdaを解除
releaseFuture.andThenConsume(Qi.onUiThread((Consumer<Void>) ignore -> {
    // Abilityの状態を保存
    abilitiesHeld = false;
    // buttonSwitchAutonomousのテキストを変更
    buttonSwitchAutonomous.setText("Hold");
    // buttonSwitchAutonomousを利用できるようにする
    buttonSwitchAutonomous.setEnabled(true);
}));
```

ConsumerオブジェクトにQi.onUiTreadを挟むと、<code>consume</code>メソッドがUIスレッドでコールバックされ、button_switch_autonomousの制御がUIスレッドで行われるようになります。


###実践
このチュートリアルのソースは[ここ](https://github.com/aldebaran/qisdk-tutorials/tree/master/app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials)から利用できます。

1. アプリケーションをインストールして実行します。
2. “Hold/release autonomous abilities”を選びます。
すると、Pepperはあなたの動きを視線で追いかけ始めるはずです。
3. button_switch_autonomousをクリックすると、Pepperは停止します。
4. 再度button_switch_autonomousをクリックすると、Pepperはまた動き始めます。