Androidアプリのユーザ補助機能を高める（前置き〜「要素にラベルを付ける」まで）

#はじめに - モバイル端末のa11yについて
Webでは活発であったアクセシビリティを踏まえた開発は近年のモバイル端末の使用者増加によって、モバイル端末でも必要とされ始めています。アプリ開発者はこれを踏まえた上での開発や、開発ずみのアプリのさらなるユーザへの改善としてユーザ補助機能を高めることが必要になってきています。

今回は自学のためandroid developers documentからユーザ補助に関するドキュメントをざっと全体をみてまとめていきます。参考は最後にリンクを貼っていますので、詳しくはそちらから見てください。

## Androidで提供されているユーザ補助機能
Androidでは端末に備わっているユーザ補助機能として以下の二つが挙げられます。

- TalkBack: 視力の弱いユーザーや目の不自由なユーザーをサポートします。合成音声でコンテンツを知らせ、ユーザーの操作に応じてアプリでアクションを実行します。
- スイッチ アクセス: 運動障がいのあるユーザーをサポートします。インタラクティブな要素をハイライト表示し、ユーザーのボタン押下に応じてアクションを実行します。1 つまたは 2 つのボタンを使用するだけでデバイスを制御できます。

([アプリのユーザー補助機能の改善に関する原則](https://developer.android.com/guide/topics/ui/accessibility/principles)より)

これにより、最低でもこの二つの機能が満足に使用できるようにアプリ開発の際には実装に交える必要があります。
この二つを含めたAndroidのユーザ補助機能については別の記事でまとめたいと思います。
一応参考にするリンクを貼り付けます。（記事を書いたらその記事のリンクにします。）

- [AndroidのTalkBack機能についてまとめる（基本操作について編）](https://qiita.com/airagu950/items/2f9eccb5c1982846beef)
- TBD
    - 参考：https://support.google.com/accessibility/android/answer/6122836

##シリーズ
1. [前置き〜「要素にラベルを付ける」まで](https://qiita.com/airagu950/items/4407afcb89944397d2ee)
2. [システムウィジェットを使用または拡張する、色以外の手がかりも取り入れる、メディア コンテンツのユーザー補助機能を強化する](https://qiita.com/airagu950/items/ff6c6572a027e16cba95)


## 改善方法
これらの機能をアプリの中で活かすために以下の方法があると紹介されています。

- 要素にラベルを付ける
- システム ウィジェットを使用または拡張する
- 色以外の手がかりも取り入れる
- メディア コンテンツのユーザー補助機能を強化する

この中で特にこの記事では「要素にラベルをつける」について見ていきます。

### 要素にラベルを付ける
アプリの操作対象（ボタンや画面遷移のUIなど）に対して簡潔で適切なラベルをつけることが推奨されています。
このラベルが特定の要素の意味と目的を明らかにすることで、ユーザ補助機能を必要とするユーザの助けになります。
先述したTalkBackなどのスクリーンリーダーはこのようなラベルを元に操作要素を読み上げることになります。そのため簡潔で的確である必要があります。

#### ラベルをつける方法とテクニック
---
- contentDescription

最も手軽で直感的なラベルの付け方です。アンドロイドではレイアウトを生成するためにxmlを使用しますが、そのレイアウトリソースファイルに直接指定します。

```text.xml
<TextView
  android:id="@+id/hoge_title"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/hoge_title"
...
  contentDescription="@string/a11y_hoge_text_title"
/>
```
こうすることによってTalkBack機能使用時、特定のUIにフォーカスが当たるタイミングでこの`contentDescription`に設定した言葉が話されます。

また動的なUIの変化がによって適切なラベルが異なる場合は、modelに持たせてxmlから参照することで適切な言葉が設定できます。

```text_model.xml

<data>

  <variable
    name="model"
    type="jp.example.android.model"/>
</data>

<TextView
  android:id="@+id/hoge_title"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/hoge_title"
...
  contentDescription="@{model.alt}"
/>
```

---
- EditTextのラベルについて

EditTeｘtを代表とする編集可能なオブジェクトの場合は、それについての説明よりも、「何を入力することが求められているのか」という有効な入力テキスト例を表示しておくと、スクリーンリーダーのような特別な補助が必要なユーザ以外の人にも有益です。このような場合は、android:hint属性をしようすることでラベルの設定ができます。

Qiitaでいうこのような入力する部分に予め薄い文字で入っており、入力する際に消える部分のことを言います。

![スクリーンショット 2020-10-29 8.40.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261466/ab5dbc12-3dea-0bf4-685a-fa195b492e8c.png)

```EditText.xml

<EditText
  android:id="@+id/hoge_edit"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/hoge_title"
...
  android:label="@string/hoge_edit_hint"
/>
```

また、EditTextの要素の前後にその要素の説明となるViewオブジェクトが存在場合は、`android:labelFor`を使用することによって、そのEditTextと関連づけて説明することができます。

``` labelFor.xml
<TextView
   android:id="@+id/usernameLabel" ...
   android:text="@string/username"
   android:labelFor="@+id/usernameEntry" />

<EditText
   android:id="@+id/usernameEntry" ... />
```

---
- コレクション内の要素

コレクション内の要素はそれぞれの要素に適切な名前がラベリングされるべきです。これにより、ユーザ補助機能の一つである読み上げ機能によって画面上の要素を適切に読み上げることができます。

たとえばRecyclerViewの場合だと、再利用するレイアウトを生成するたびに適切なラベルをつける必要があります。この実装のためには、先述したmodelにaltanativeの要素を持たせてcontentDescriptionに設定する他、アダプター実装の一部として設定することもできます。

``` collection_adapter.kt
data class MovieRating(val title: String, val starRating: Integer)

class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {

    class MyRatingViewHolder(val ratingView: ImageView) :
            RecyclerView.ViewHolder(ratingView)

    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"
    }
}
```

---
- 関連コンテンツのグループ
関連したコンテンツをUIとして作成する場合、いちいち細切れにフォーカスが当たって読み上げられるとかえってわかりにくい場合があります。
公式のドキュメントでは曲の詳細が例として挙げられていましたが、

たとえばDISH//の猫についての説明をTalkBackにて行う場合に
![スクリーンショット 2020-10-29 8.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261466/81cb6ba4-6964-dfe0-4520-9f0996f0a727.png)

「曲名：猫」
→次への操作

「アーティスト：DISH//」
→次への操作

「アルバム：僕たちがやりました」
→次への操作

「リリース：２０１７年」
→次への操作

「ジャンル：J-POP」
→次への操作で次の曲へ移動、以下これの繰り返し


となるのではあまりに煩わしいです。これを

「曲名：猫、アーティスト：DISH//,アルバム：僕たちがやりました、リリースは2017年でジャンルはJ-POPです」
と一度に説明された方が操作する方も煩わしさを感じずに済むかと思います。
これを実現するのが`android:screenReaderFocusable`です。
一連の説明が入ったlayoutに対して`android:screenReaderFocusable="true"`を設定し、子要素に対して`android:focusable="false"`を設定することで、子要素に対してフォーカスが当たることなくTalkBackを操作することができます。

``` focusable.xml
<ConstraintLayout
    android:id="@+id/hoge_container" ...
    android:screenReaderFocusable="true">

    <TextView
        android:id="@+id/hoge_1" ...
        android:focusable="false"
        android:text="@string/hoge_1" />
    <TextView
        android:id="@+id/hoge_2"
        android:focusable="false"
        android:text="@string/hoge_2" />
</ConstraintLayout>
```

---
- テキスト内の見出し

TalkBackでは読み上げる要素の粒度を選択することができます。
たとえば見出しのみを読み上げることなどある程度の塊から詳細にそって、自分の興味のある分野を探し、それにフォーカスして読み上げを使用する機能が存在します。
この機能をうまく使用するために、実装者は意図的に見出しを作成することができます。そうすることでユーザに対してある程度のグループについての説明を行うことができます。
`android:accessibilityHeading`属性をtrueにすることで、実装者はそのviewを見出しに設定することができます。


``` accessibilityHeading.xml
<ConstraintLayout
    android:id="@+id/hoge_container" ...
    android:accessibilityHeading="true">

    <TextView
        android:id="@+id/hoge_1" ...
        android:focusable="false"
        android:text="@string/hoge_1" />
    <TextView
        android:id="@+id/hoge_2"
        android:focusable="false"
        android:text="@string/hoge_2" />
</ConstraintLayout>
```

---
- ユーザ補助ペインの見出し


Android 9（API レベル 28）以上では、ペイン（表示領域）全体に対して一つの見出しをつけることができます。
`android:accessibilityPaneTitle`を使用することで、実装者はその画面全体のタイトルをユーザにつたえることができるので、詳細な説明をすることなく、ユーザの画面の意図を伝えることができます。

```pane_title.xml
<HogeView
     android:id="@+id/shoppingCartContainer"
     android:accessibilityPaneTitle="@string/hoge_pane_title" ... />
```

---
- 装飾的要素
（説明不要、[原文ママ](https://developer.android.com/guide/topics/ui/accessibility/principles#decorative)）

UI 内のある要素が視覚的な間隔をあけるため、または見た目のためにのみ存在する場合、その android:contentDescription 属性を "null" に設定してください。

Android 4.1（API レベル 16）以上を搭載するデバイスのみをサポートするアプリの場合は、代わりにこうした純粋に装飾的な要素の android:importantForAccessibility 属性を "no" に設定できます。



## おわりに
今回はandroid developer documentの中の前置きから「要素にラベルをつける」までを紹介しました。
今後のシリーズとしてドキュメントの中にある他の補助機能を高める方法についてもまとめます。
興味がある方は、次も読んでいただければと思います。ありがとうございました。

### 次からの記事では以下の点についてまとめていきます。
- システム ウィジェットを使用または拡張する
- 色以外の手がかりも取り入れる
- メディア コンテンツのユーザー補助機能を強化する

今回：[Androidアプリのユーザ補助機能を高める（前置き〜「要素にラベルを付ける」まで）](https://qiita.com/airagu950/items/4407afcb89944397d2ee)
次回：[Androidアプリのユーザ補助機能を高める（システム ウィジェットを使用または拡張する 〜 メディア コンテンツのユーザー補助機能を強化する）](https://qiita.com/airagu950/items/ff6c6572a027e16cba95)


# 参考
https://developer.android.com/guide/topics/ui/accessibility/apps
https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor
https://developer.android.com/guide/topics/ui/accessibility/custom-views
https://developer.android.com/guide/topics/ui/accessibility/service
https://developer.android.com/guide/topics/ui/accessibility/principles
https://developer.android.com/guide/topics/ui/accessibility/testing
https://android-developers.googleblog.com/2012/04/accessibility-are-you-serving-all-your.html