Fire OSにユーザー補助機能を実装する方法


Fire OSにユーザー補助機能を実装する方法

このページでは、Fire OSのユーザー補助機能の実装に関連する概念と用語について説明します。

Fire OSのユーザー補助オブジェクトとイベントの概要

このセクションでは、アプリにユーザー補助機能を実装するときに使用するオブジェクトやイベントに関する用語とそれらの定義を紹介します。

AccessibilityEvent

AccessibilityEventは、UIで何かが行われたことを表す、アプリからユーザー補助機能へのメッセージです。ユーザー補助イベントをトリガーするUIの変化には、フォーカスの変化、ウィンドウの表示や非表示、画面上のオブジェクトの位置の変化などがあります。

AndroidドキュメントのAccessibilityEventsを参照してください。

AccessibilityNodeInfo

AccessibilityNodeInfoは、画面上のコンポーネントに関するユーザー補助情報のスナップショットです。ほとんどの場合、アプリからユーザー補助機能への一方向の通信です。ごくまれですが、ユーザー補助アクションを介してユーザー補助機能からアプリに情報が返されることもあります。

アプリによってAccessibilityNodeInfoが作成されて返されると、それ以降はユーザー補助の機能とフレームワークで当該ノードに対する変更が確認されなくなるため、その時点でノードを破棄できます。ノードが表す基礎オブジェクトが変更された場合は、変更を示す適切なユーザー補助イベントを送信してください。その際、createAccessibilityNodeInfoまたはonInitializeAccessibilityNodeInfoへの次の呼び出しで返されるノード内のオブジェクトを確認し、特性の更新内容をイベントに反映してください。

アプリでは、サーバー側でのノードの参照に、Androidビューと仮想子孫番号を組み合わせて使用してください。ノードがビュー自体を表している場合、仮想子孫番号は-1 (AccessibilityNodeProvider.HOST_VIEW_ID)になります。

アプリでは、AccessibilityNodeInfoオブジェクトに関する説明情報をそのオブジェクトのgetExtras Bundleに追加できます。VoiceViewは、AccessibilityNodeInfo.getExtras()を呼び出して、この情報を読み取ることができます。

AndroidドキュメントのAccessibilityNodeInfoを参照してください。

AccessibilityNodeProvider

AccessibilityNodeProviderは、あるビューの、またはあるビューの仮想的にアクセス可能な子孫のAccessibilityNodeInfoを作成するインターフェイスです。

AndroidドキュメントのAccessibilityNodeProviderを参照してください。

AccessibilityDelegate

AccessibilityDelegateは、イベント、ビューのノード、または仮想的にアクセス可能な子孫を初期化できるインターフェイスです。AccessibilityDelegatesを使用すると、あるビューのユーザー補助情報を別のビューで代替や補完として利用することができます。たとえば、親リストでリスト項目のユーザー補助情報を提供できます。

AndroidドキュメントのAccessibilityDelegateを参照してください。

ユーザー補助イベントへのパス

このセクションでは、標準ビューおよびカスタマイズビューのユーザー補助イベントへのパスについて説明します。

標準ビュー

Fire OSアプリのユーザーインターフェイスを構成する視覚的要素をビューと呼びます。たとえば、1つのテキスト要素を持つ(TextViewで"hello world"というテキストを表示する)簡単なアプリがあるとします。このとき、TextViewRelativeLayoutの子であるとします。RelativeLayoutは、常にアプリのビュー階層のルートとなるクラスViewRootImplの子です。TextViewは標準のAndroidビューであるため、TextViewは、デフォルトの動作として、VoiceView実行時に適切なユーザー補助イベントを送信します。

次のプロセスは、この簡単なアプリ内に作成されたユーザー補助イベントのパスを示します。 

  1. アプリが開かれてから数秒後に、アプリのコードがtextView.setText("new text")を呼び出します。
  2. TextViewTYPE_WINDOW_CONTENT_CHANGEDというAccessibilityEventを作成し、このイベントを送信するよう親のRelativeLayoutにリクエストします。
  3. RelativeLayoutがイベントを親のViewRootImplに渡し、フレームワークに送信するようリクエストします。
  4. ViewRootImplが、AccessibilityManagersendAccessibilityEvent()を呼び出して、イベントをユーザー補助フレームワークに送信します。
  5. AccessibilityManagerがイベントをAccessibilityManagerServiceに渡し、AccessibilityManagerServiceはユーザー補助フレームワークからVoiceViewにイベントを渡します。
  6. VoiceViewはTYPE_WINDOW_CONTENT_CHANGED AccessibilityEventを処理する際に、イベントオブジェクトのgetSource()メソッドを呼び出します。
  7. このメソッドがトリガーとなり、ユーザー補助フレームワークがTextViewのcreateAccessibilityNodeInfo()メソッドを呼び出します。このメソッドは、"new text"が含まれたAccessibilityNodeInfoオブジェクトを返します。
  8. ユーザー補助フレームワークが、AccessibilityNodeInfoオブジェクトをVoiceViewに返します。
  9. 最後に、TextViewが"hello world"から"new text"に変更されたことを、VoiceViewが認識します。ユーザーがリニアナビゲーションを使用してTextViewのテキストを読み上げさせると、VoiceViewは"new text"を正しく読み上げます。

カスタマイズビュー

アプリで標準ビューの代わりにカスタマイズビューを使用する場合、VoiceViewにウィジェットの状態を通知するためのパターンを守る必要があります。通知する際、AccessibilityNodeInfoオブジェクトをVoiceViewに送信したり、アプリ内のAccessibilityNodeInfoのローカルコピーを更新したりしないでください。これらの方法は機能しません。

カスタマイズウィジェットの状態を変更するとき:

すべきこと

  • カスタマイズビューの親で、requestSendAccessibilityEvent()を呼び出すことでAccessibilityEventを送信します。
  • カスタマイズビューのcreateAccessibilityNodeInfo()関数内で参照されている変数に、更新された値が含まれていることを確認してください。VoiceViewはAccessibilityEventを受け取ると、createAccessibilityNodeInfo()を呼び出します。

してはいけないこと

  • VoiceViewにAccessibilityNodeInfoを送信してみないでください。
  • AccessibilityNodeInfoオブジェクトへのリファレンスがcreateAccessibilityNodeInfo()関数に含まれていない状態で、このオブジェクトを更新しないでください。VoiceViewにはこのオブジェクトを参照する手段がないため、このオブジェクトの更新を確認できません。

Androidのドキュメントで、AccessibilityDelegateクラスと、createAccessibilityNodeInfo()関数が実装されているAccessibilityNodeProviderクラスの正しい使い方を示したコード例を確認してください。

ビューの重要度を設定

ユーザー補助イベントが適切に処理されるように、Androidビューごとにユーザー補助の重要度を設定してください。 

ユーザー補助におけるビューの重要度は、XMLレイアウトでandroid:importantForAccessibility属性を使用するか、プログラムでView.setImportantForAccessibilityメソッドを使用して設定します。設定できる値は、yes、no、no_hide_descendantsauto(デフォルト)です。重要でない値が設定されたビューには、対応するユーザー補助ノードが作成されません。また、そのビューから送信されたユーザー補助イベントは、フレームワークによって破棄されます。

ビューが適切なユーザー補助イベントを送信していても、VoiceViewが正しく応答していないと思われる場合は、ビューがユーザー補助にとって重要であると設定されているかどうかを確認してください。

AccessibilityNodeInfoオブジェクトを管理

Fire OSとAndroidのユーザー補助の重要な要素の1つは、AccessibilityNodeInfoオブジェクトの管理です。アプリのプロセスで実行されるAndroidのユーザー補助フレームワークが特定のノードの要求を受け取ると、フレームワークはまずそのノードがキャッシュ内にあるかどうかを確認します。

  • ノードがキャッシュに存在する場合はそれが返され、アプリでノードを作成する呼び出しは行われません。そのため、コンポーネントに関するユーザー補助情報が変更されるたびに、アプリはフレームワークとユーザー補助機能に通知する必要があります。通知しない場合、フレームワークは古い情報をユーザー補助機能に返します。
  • ノードが変更されて無効になったことを示すには、AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGEDタイプのユーザー補助イベントを送信します。
  • ノードがまだキャッシュにない場合は、要求された方法に応じてノードが作成されます。ユーザー補助機能による次のアクションがAccessibilityNodeInfoオブジェクトの作成をトリガーできます。
    • ユーザー補助イベントを受け取り、そのソースを要求する。
    • アクティブなウィンドウのルートノードを要求する。
    • 特定のノードの親ノードまたは子ノードを要求する。

仮想的にアクセス可能な子孫を実装

このセクションでは、仮想的にアクセス可能な子孫ビューを実装する方法について説明します。

仮想的にアクセス可能な子孫ビューを作成する

AccessibilityDelegateAccessibilityNodeProviderはどちらも、基盤のビューで表現されない画面コンポーネントにユーザー補助機能を提供できます。このようなコンポーネントの例には、キーがキャンバス上に描画されるAOSPのオンスクリーンキーボードがあります。仮想ノードツリーを実装すると、Androidが提供するExploreByTouchHelperサポートライブラリが期待どおりに動作しないことがあります。

アプリは、ノードをホストしているビューと仮想ビューIDを使用してAccessibilityNodeInfoオブジェクトを参照します。仮想ビューIDが-1 (AccessibilityNodeProvider.HOST_VIEW_ID)の場合は、ホストビュー自体が参照されます。ノードを作成する際に仮想子を追加するには、AccessibilityNodeInfo.addChild()メソッドを使用し、ホストビューと、仮想子の仮想ビューIDを指定します。同様に、子ノードを作成する際に仮想親ビューを設定するには、AccessibilityNodeInfo.setParent()の呼び出しでホストビューと親仮想ビューIDを指定します。

仮想的にアクセス可能な子孫ビューを管理する

仮想ビューは、最初の作成直後は、自身のIDでのみ参照され、関連するユーザー補助情報(テキスト、コンテンツの説明など)を持っていません。ユーザー補助フレームワークがアプリに対して適切なノードを作成するようリクエストすると、対応するユーザー補助情報がAccessibilityNodeInfoに入力されます。そのため、どの仮想ビューIDがカスタマイズウィジェットのどの部分を表しているかをアプリが追跡するようにしてください。

子ノードまたは親ノードのIDを追加すると、フレームワークがアプリに対して実際にこれらのノードを作成するようリクエストします。コンテナノードに子ノードを追加しないでください。

Fire OSのユーザー補助機能に関するベストプラクティス

ユーザー補助機能が搭載されたアプリのユーザーエクスペリエンスを高めるには、次のガイドラインに従います。

  • AccessibilityNodeInfoのテキストAccessibilityNodeInfoのテキストが、オブジェクトの画面上のテキストのみを返すようにしてください。
  • 画面上のアイテムのラベル: 画面上の重要なアイテムには、すべてラベルを付けてください。VoiceViewをテストするときは、すべての画面上のアイテムをタップして、適切な説明が読み上げられるかを確認してください。説明が欠けている場合は、適切なテキストやコンテンツの説明をアイテムのAccessibilityNodeInfoに追加する必要があります。
  • コンテンツの説明: 画面上のテキストがないアイテムには、コンテンツの説明(画像の代替テキストなど)を使用してください。または、画面上のテキストを補完するために、追加の文脈情報をユーザーに提供することもできます。ただし、ユーザーが困惑するほど多くの情報をコンテンツの説明に加えないようにしてください。
  • ユーザー補助イベントの使用: 画面上のアクティビティを伝えるために、AccessibilityEvent.TYPE_ANNOUNCEMENTイベントタイプを使用しないでください。画面上の変化に関する情報を伝える方法としては、相当する変更をAccessibilityNodeInfoに加えてユーザー補助イベントと組み合わせることが推奨されます。