多くの Android TV アプリはネイティブの Android コンポーネントで構築されていますが、特に カスタムビューを使用する場合は、サードパーティのフレームワークやコンポーネントのユーザー補助機能も考慮することが 重要です。
OpenGL または Canvas と直接やり取りするカスタムビュー コンポーネントは、Talkback やスイッチ アクセスなどのユーザー補助サービスとうまく連携できない場合があります。
Talkback をオンにした場合に発生する可能性のある問題について、以下にいくつか示します。
- アプリでユーザー補助フォーカス(緑色の長方形)が表示されなくなることがあります。
- ユーザー補助フォーカスが画面全体の境界を選択することがあります。
- ユーザー補助フォーカスを移動できないことがあります。
- コードで処理していても、D-pad の 4 方向キーが機能しないことがあります。
アプリでこれらの問題が発生した場合は、アプリが
AccessibilityNodeInfo ツリーをユーザー補助サービスに公開していることを確認してください。
このガイドの残りの部分では、これらの問題に対処するための解決策とベスト プラクティスについて説明します。
D-pad イベントがユーザー補助サービスによって使用される
この問題の根本的な原因は、キーイベントがユーザー補助サービスによって使用されることです。
図 1 に示すように、Talkback がオンの場合、D-pad イベントはデベロッパーが定義した D-pad ハンドラに渡されません。代わりに、ユーザー補助サービスがキーイベントを受信して、ユーザー補助フォーカスを移動できるようにします。 カスタム Android コンポーネントは、画面上の位置に関する情報をデフォルトでユーザー補助サービスに公開しないため、ユーザー補助サービスはユーザー補助フォーカスを移動してハイライト表示することができません。
他のユーザー補助サービスも同様に影響を受けます。スイッチ アクセスを使用している場合も、D-pad イベントが使用されることがあります。
D-pad イベントはユーザー補助サービスに送信されますが、そのサービスはカスタムビュー内の UI コンポーネントの位置を認識していません。そのため、キーイベントを正しく転送するには、アプリに AccessibilityNodeInfo を実装する必要があります。
ユーザー補助サービスに情報を公開する
カスタムビューの位置
と説明に関する十分な情報をユーザー補助サービスに提供するには、AccessibilityNodeInfo を実装して、
各コンポーネントの詳細を公開します。ユーザー補助サービスがフォーカスを管理できるようにビューの論理的な関係を定義するには、
ExploreByTouchHelper を実装し、カスタムビューに
ViewCompat.setAccessibilityDelegate(View, AccessibilityDelegateCompat)
を使用して設定します。
ExploreByTouchHelper を実装する場合は、次の 4 つの抽象メソッドをオーバーライドします。
Kotlin
// Return the virtual view ID whose view is covered by the input point (x, y).
protected fun getVirtualViewAt(x: Float, y: Float): Int
// Fill the virtual view ID list into the input parameter virtualViewIds.
protected fun getVisibleVirtualViews(virtualViewIds: List<Int>)
// For the view whose virtualViewId is the input virtualViewId, populate the
// accessibility node information into the AccessibilityNodeInfoCompat parameter.
protected fun onPopulateNodeForVirtualView(virtualViewId: Int, @NonNull node: AccessibilityNodeInfoCompat)
// Set the accessibility handling when perform action.
protected fun onPerformActionForVirtualView(virtualViewId: Int, action: Int, @Nullable arguments: Bundle): Boolean
Java
// Return the virtual view ID whose view is covered by the input point (x, y).
protected int getVirtualViewAt(float x, float y)
// Fill the virtual view ID list into the input parameter virtualViewIds.
protected void getVisibleVirtualViews(List<Integer> virtualViewIds)
// For the view whose virtualViewId is the input virtualViewId, populate the
// accessibility node information into the AccessibilityNodeInfoCompat parameter.
protected void onPopulateNodeForVirtualView(int virtualViewId, @NonNull AccessibilityNodeInfoCompat node)
// Set the accessibility handling when perform action.
protected boolean onPerformActionForVirtualView(int virtualViewId, int action, @Nullable Bundle arguments)
詳細については、Google I/O 2013 - Enabling Blind and Low-Vision Accessibility on Android をご覧いただくか、ユーザー補助 イベントの入力についての記事をご覧ください。
ベスト プラクティス
必須:
AccessibilityNodeInfo.getBoundsInScreen()でコンポーネントの位置を定義する必要があります。必須:
AccessibilityNodeInfo.setVisibleToUser()でコンポーネントの可視性を反映する必要があります。必須:
AccessibilityNodeInfo.getContentDescription()で、Talkback が読み上げるコンテンツの説明を指定する必要があります。AccessibilityNodeInfo.setClassName()を指定して、サービスが コンポーネント タイプを区別できるようにします。performAction()を実装する場合は、対応するAccessibilityEventを使用してアクションを反映します。ACTION_CLICKなどのアクション タイプを実装するには、AccessibilityNodeInfo.addAction(ACTION_CLICK)の対応するロジックを使用してperformAction()を呼び出します。該当する場合は、
setFocusable()、setClickable()、setScrollable()などのメソッドでコンポーネントの状態を反映します。AccessibilityNodeInfoのドキュメントを確認して、ユーザー補助サービスがコンポーネントとより適切に連携できる他の 方法を特定します。
サンプル
カスタムビューを使用するアプリにユーザー補助サポートを追加するためのベスト プラクティスについては、Android TV のカスタムビューのユーザー補助のサンプルをご覧ください。