この記事では、VHAL でロータリー入力を処理する方法、ロータリー サービスを含めるようにビルドを設定する方法、すべてのアプリでロータリー エクスペリエンスをカスタマイズする方法について説明します。OEM 提供のランチャーなど、プリインストールされた OEM アプリについては、Car UI ライブラリ(car-ui-library)をご覧ください。
VHAL
ロータリー コントローラでは次のアクションがサポートされています。
- 上下左右に移動する。
- 時計回り / 反時計回りに回転する。
- 中央ボタンを押す。
- 戻るボタンを押す。
- ホームボタンを押す。
- その他のボタン(電話やメディアなど)を押す。
システム プロパティと、対応する int32Values
のドキュメントについては、hardware/interfaces/automotive/vehicle/2.0/types.hal
をご覧ください。
VHAL は以下のアクションを処理します。
移動
ユーザーがロータリー コントローラを右に押すと、VHAL は次の int32Values
を指定して HW_KEY_INPUT
プロパティを使用し、Android にイベントを送信します。
ACTION_DOWN
KEYCODE_SYSTEM_NAVIGATION_RIGHT
- ターゲット ディスプレイ。
ユーザーがロータリー コントローラを離すと、VHAL は ACTION_UP
を指定して同じプロパティとキーコードを使用します。別の方向への移動では、対応するキーコードを使用します。
対角線のキーコードはありませんが、ハードウェアが対角線をサポートしている場合、VHAL は水平イベントと垂直イベントを組み合わせて対角線を生成できます。たとえば、左と上に移動した場合は次のようになります。
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
いずれかの順番で(続けて)ロータリー コントローラを離すと、次のようになります。
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
ユーザーはロータリー コントローラを離す前に垂直方向に押すことがあります。 たとえば、次のシナリオをご覧ください。
これにより、次のイベント シーケンスが生成されます。
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
ロータリー コントローラが 1 つの方向に押されているときに、繰り返しイベントが生成されないようにしてください。
回転
ユーザーがロータリー コントローラを時計回りに 1 デテント(クリック)回転すると、VHAL は次の int32Values
を指定して HW_ROTARY_INPUT
プロパティを使用し、イベントを Android に送信します。
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- 1 デテント。
- ターゲット ディスプレイ。
イベントのタイムスタンプは、ナノ秒単位の経過時間に設定する必要があります。
反時計回りの回転を 1 デテント行うと、同じイベントが生成されますが、デテントの数は -1 になります。
同方向への回転で複数のデテントが連続して発生する場合、VHAL はシステムに過剰な負荷がかからないように、各デテントを 1 つのイベントに結合します。この場合、イベントのタイムスタンプは、回転のデテントが最初に発生したときの時刻になります。
int32Values
には、連続する回転のデテント間のナノ秒数を含める必要があります。
たとえば、次の一連の回転があるとします。
- t0 の時刻に、ユーザーは反時計回りに 1 デテント回転しました。
- t0 + 5 ns の時刻に、ユーザーは反時計回りに 1 デテント回転しました。
- t0 + 8 ns の時刻に、ユーザーは反時計回りに 1 デテント回転しました。
上記の回転により、次のイベントが生成されます。
- プロパティ:
HW_ROTARY_INPUT
- タイムスタンプ:
t0
int32Values
:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
- -3(反時計回りに 3 デテント)
- ターゲット ディスプレイ。
- 1 回目と 2 回目のデテントの間の 5 ns。
- 2 回目と 3 回目のデテントの間の 3 ns。
中央ボタン
ユーザーが中央ボタンを押すと、VHAL は次の int32Values
を指定して HW_KEY_INPUT
プロパティを使用し、Android にイベントを送信します。
ACTION_DOWN
KEYCODE_DPAD_CENTER
- ターゲット ディスプレイ。
ユーザーがロータリー コントローラを離すと、VHAL は ACTION_UP
を指定して同じプロパティとキーコードを使用します。
中央ボタンが押されているときに繰り返しイベントを生成しないでください。
戻るボタン
ユーザーが戻るボタンを押すと、VHAL は次の int32Values
を指定して HW_KEY_INPUT
プロパティを使用し、Android にイベントを送信します。
ACTION_DOWN
KEYCODE_BACK
- ターゲット ディスプレイ。
ユーザーがロータリー コントローラを離すと、VHAL は ACTION_UP
を指定して同じプロパティとキーコードを使用します。
中央ボタンが押されているときに繰り返しイベントが生成されないようにしてください。
ホームボタン
ホームボタンは戻るボタンと同じように処理しますが、KEYCODE_BACK
ではなく KEYCODE_HOME
を使用します。
その他のボタン
ロータリー コントローラにその他のボタンが含まれている場合、Android の観点からはロータリーの一部とは見なされないため、OEM は VHAL によってそれらのボタンをどのようにでも処理できます。これらは通常、戻るボタンやホームボタンと同様に処理されますが、異なるキーコード(KEYCODE_CALL
や KEYCODE_MUSIC
など)が使用されます。
ビルド構成
ロータリー ナビゲーションは、RotaryService
というユーザー補助サービスによって提供されます。
デバイスのシステム イメージにこのサービスを含めるには、makefile に次の行を追加します。
PRODUCT_PACKAGES += CarRotaryController
デバッグビルドに次のパッケージを含めることもできます。
RotaryPlayground
: ロータリーのリファレンス アプリ(RotaryPlayground を参照)。RotaryIME
: デモのロータリー IME(インプット メソッド エディタを参照)。CarRotaryImeRRO
:RotaryIME
のオーバーレイ。
ロータリー サービスは、デバイスの起動時とユーザーの切り替え時に自動的に有効になります。これにより、ユーザーはセットアップ中にロータリー コントローラを使用できるようになります。
ロータリー コントローラの有無にかかわらず、同じビルドを自動車に使用する場合は、上記のように CarRotaryController
を追加して、必要なコードがビルドに含まれるようにします。ロータリーのない自動車でロータリー サービスが有効化されないようにするには、静的 RRO を作成して、packages/services/Car/service
の rotaryService
文字列リソースを空の文字列でオーバーレイします。ロータリー デバイスと非ロータリー デバイスでは同じビルドを使用しますが、プロダクト構成が異なります。オーバーレイが含まれているのは後者のみです。
カスタマイズ
OEM は、次の場所にあるリソース オーバーレイを使用して、フォーカス検出ロジック、フォーカス ハイライト、その他のアイテムをカスタマイズできます。
- car-ui-library は
packages/apps/Car/libs/car-ui-lib
にあります。 RotaryService
はpackages/apps/Car/RotaryController
にあります。Core
はframeworks/base/core
にあります。
移動履歴
OEM は、2 種類の移動履歴をそれぞれ有効にするかどうかと、有効にした場合のキャッシュ サイズと有効期限ポリシーを構成できます。これはすべて、各種の car-ui-library リソースをオーバーライドすることで行います。
フォーカス履歴のキャッシュ
(Android 11 QPR3、Android 11 Car、Android 12)
この FocusArea
単位のキャッシュには、FocusArea
に戻るときにフォーカスできるように、FocusArea
内で最後にフォーカスされたビューが保存されます。このキャッシュは、次の car-ui-library リソースをオーバーレイすることで構成できます。
-
car_ui_focus_history_cache_type
:- キャッシュが無効になっています。
- しばらくするとキャッシュが期限切れになります(以下を参照)。
- キャッシュに有効期限はありません。
car_ui_focus_history_expiration_period_ms
: キャッシュ タイプが 2 に設定されている場合に、キャッシュが期限切れになるまでのミリ秒数(上記参照)。
FocusArea の履歴のキャッシュ
(Android 11 QPR3、Android 11 Car、Android 12)
このキャッシュには、反対方向に移動したときに同じ FocusArea
にフォーカスを戻せるように、移動の履歴が保存されています。このキャッシュは、次の car-ui-library リソースをオーバーレイすることで構成できます。
-
car_ui_focus_area_history_cache_type
:- キャッシュが無効になっています。
- しばらくするとキャッシュが期限切れになります(以下を参照)。
- キャッシュに有効期限はありません。
car_ui_focus_area_history_expiration_period_ms
: キャッシュ タイプが 2 に設定されている場合に、キャッシュが期限切れになるまでのミリ秒数(上記参照)。car_ui_clear_focus_area_history_when_rotating
: ユーザーがコントローラを回転させたときにキャッシュを無効にするかどうか。
回転
(Android 11 QPR3、Android 11 Car、Android 12)
OEM は、RotaryService
内の 2 つの整数リソースをオーバーライドして、アクセラレーションの有無を指定できます。これには、次のような回転時のマウス アクセラレーションなどがあります。
rotation_acceleration_3x_ms
: Google が回転のデテントでコントローラの回転を加速するかどうかを決定するために使用される時間間隔(ミリ秒単位)。このデテントと前の回転デテントの間の間隔がこの値より小さい場合は、3 回の回転デテントとして扱われます。3 倍のアクセラレーションを無効にするには、この値を 2147483647 に設定します。rotation_acceleration_2x_ms
:rotation_acceleration_3x_ms
に似ており、2 倍のアクセラレーションに使用されます。2 倍のアクセラレーションを無効にするには、これを2147483647
に設定します。
アクセラレーションは、VHAL で要求されるとおり、回転の各デテントに個別のタイムスタンプがある場合に最適に動作します。タイムスタンプを使用できない場合、RotaryService
は、回転のデテントが等間隔であると想定します。
/** * Property to feed H/W rotary events to android * * int32Values[0] : RotaryInputType identifying which rotary knob rotated * int32Values[1] : number of detents (clicks), positive for clockwise, * negative for counterclockwise * int32Values[2] : target display defined in VehicleDisplay. Events not * tied to specific display must be sent to * VehicleDisplay#MAIN. * int32values[3 .. 3 + abs(number of detents) - 2]: * nanosecond deltas between pairs of consecutive detents, * if the number of detents is > 1 or < -1 * * VehiclePropValue.timestamp: when the rotation occurred. If the number of * detents is > 1 or < -1, this is when the * first detent of rotation occurred. * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @data_enum RotaryInputType * @access VehiclePropertyAccess:READ */ HW_ROTARY_INPUT = ( 0x0A20 | VehiclePropertyGroup:SYSTEM | VehiclePropertyType:INT32_VEC | VehicleArea:GLOBAL),
フォーカス ハイライト
OEM は、Android フレームワークのデフォルトのフォーカス ハイライトと、car-ui-library のいくつかのフォーカス ハイライト リソースをオーバーライドできます。
デフォルトのフォーカス ハイライト
Android フレームワークでは、属性 selectableItemBackground
を通じてデフォルトのフォーカス ハイライトが提供されます。Theme.DeviceDefault
では、この属性は Core
の item_background.xml
を参照します。OEM は、item_background.xml
をオーバーレイして、デフォルトのフォーカス ハイライト ドローアブルを変更できます。
通常、このドローアブルは StateListDrawable
で、これにより android:state_focused
や android:state_pressed
など、さまざまな状態の組み合わせに基づいて背景を調整します。ユーザーがロータリー コントローラを使用してビューにフォーカスを設定すると、android:state_focused
は true
になりますが、android:state_pressed
は false
になります。その後ユーザーがロータリー コントローラの中央ボタンを押すと、ボタンを押している間は android:state_focused
と android:state_pressed
の両方が true
になります。ユーザーがボタンを離すと、android:state_focused
のみが true
のままになります。
car-ui-library は、Theme.DeviceDefault
から派生したテーマを使用しています。そのため、このオーバーレイは、このライブラリを使用するアプリや、Theme.DeviceDefault
から派生したテーマを使用するアプリに影響します。無関係なテーマ(Theme.Material
など)を使用するアプリには影響しません。
car-ui-library のフォーカス ハイライト リソース
OEM は、複数の car-ui-library リソースをオーバーライドして、長方形以外(丸やピル型など)のフォーカス ハイライトがあるビューと、Theme.DeviceDefault
から派生していないテーマを使用するアプリで、フォーカス ハイライトをどのように表示するかを制御できます。これらのリソースは、フォーカス ハイライトがデフォルトのフォーカス ハイライト ドローアブルと一致するようにオーバーレイする必要があります。
(Android 11 QPR3、Android 11 Car、Android 12)。
次のリソースは、ビューがフォーカスされているが、押されていない状態を示すために使用されます。
car_ui_rotary_focus_fill_color
: 塗りつぶしの色。car_ui_rotary_focus_stroke_color
: 枠線の色。car_ui_rotary_focus_stroke_width
: 枠線の太さ。
(Android 11 QPR3、Android 11 Car、Android 12)
次のリソースは、ビューがフォーカスされ、かつ押されている状態を示すために使用されます。
car_ui_rotary_focus_pressed_fill_color
: 塗りつぶしの色。car_ui_rotary_focus_pressed_stroke_color
: 枠線の色。car_ui_rotary_focus_pressed_stroke_width
: 枠線の太さ。
次の例に示すように、ユーザーの注意を引くためにボタンに無地の背景色が使用されることがあります。これにより、フォーカス ハイライトが見づらくなります。
その場合、デベロッパーはセカンダリ カラーを使用してカスタム フォーカス ハイライトを指定できます。
- (Android 11 QPR3、Android 11 Car、Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12)
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
たとえば、塗りつぶしのみ、または枠線のみが必要な場合は、任意の色を透明にしたり、いずれかのサイズをゼロにしたりできます。
FocusArea のハイライト
(Android 11 QPR3、Android 11 Car、Android 12)FocusArea
は、子孫の 1 つがフォーカスされた場合に 2 種類のハイライトを描画できます。必要に応じて両方を組み合わせて使用することも可能です。この機能は、AOSP ではデフォルトで無効になっていますが、car-ui-library リソースをオーバーライドすることで有効にできます。
car_ui_enable_focus_area_foreground_highlight
:FocusArea
とその子孫の上にハイライトを描画します。AOSP では、このドローアブルはFocusArea
を囲む枠線です。OEM は、car_ui_focus_area_foreground_highlight
ドローアブルをオーバーライドできます。car_ui_enable_focus_area_background_highlight
:FocusArea
の上、子孫の背後にハイライトを描画します。AOSP では、このドローアブルは単色塗りつぶしです。 OEM は、car_ui_focus_area_background_highlight
ドローアブルをオーバーライドできます。
インプット メソッド エディタ
インプット メソッド エディタ(IME)とは、画面キーボードなどの入力方法のことです。
(Android 11 QPR3、Android 11 Car、Android 12)
OEM は、RotaryService
内の default_touch_input_method
文字列リソースをオーバーレイすることで、タッチベースの IME の ComponentName
を指定する必要があります。たとえば、OEM が Android Automotive で提供される IME を使用する場合は、com.google.android.apps.automotive.inputmethod/.InputMethodService
を指定する必要があります。
(Android 11 QPR3、Android 11 Car、Android 12)。
OEM がロータリー専用の IME を作成した場合は、rotary_input_method
リソースで ComponentName
を指定する必要があります。このリソースがオーバーレイされている場合、ユーザーがロータリー コントローラの移動、回転、中央ボタンでヘッドユニットを操作するたびに、指定された IME が使用されます。ユーザーが画面に触れると、以前の IME が使用されます。戻るボタン(およびロータリー コントローラのその他のボタン)が IME の選択に影響することはありません。このリソースがオーバーレイされていない場合、IME の切り替えは行われません。Carboard はロータリー コントローラをサポートしていないため、OEM がロータリー IME を提供していない場合、ユーザーはロータリー コントローラからテキストを入力できません。
RotaryIME
はデモのロータリー IME です。基本的な機能しか備えていないものの、上記のような IME の自動的な切り替えを試すには十分です。RotaryIME
のソースコードは packages/apps/Car/tests/RotaryIME/
にあります。
画面外への移動
デフォルトでは、ユーザーが画面外に移動しようとしても何も起こりません。OEM は、以下の組み合わせを指定して、4 つの方向それぞれに対する処理を設定できます。
AccessibilityService
で定義されたグローバル アクション(GLOBAL_ACTION_BACK
など)。- キーコード(
KEYCODE_BACK
など)。 - URL で表されるアクティビティを起動するインテント。
(Android 11 QPR3、Android 11 Car、Android 12)
これらは、RotaryService
で次の配列リソースをオーバーレイすることで指定します。
off_screen_nudge_global_actions
: ユーザーが画面外に向けて上下左右に移動するときに実行するグローバル アクションの配列。この配列の関連要素が -1 の場合、グローバル アクションは行われません。off_screen_nudge_key_codes
: ユーザーが画面外に向けて上下左右に移動するときに挿入するクリック イベントのキーコードの配列。この配列の関連要素が 0(KEYCODE_UNKNOWN
)の場合、イベントは挿入されません。off_screen_nudge_intents
: ユーザーが画面外に向けて上下左右に移動するときにアクティビティを起動するインテントの配列。この配列の関連要素が空の場合、アクティビティは起動されません。
その他の構成
次の RotaryService
リソースをオーバーレイする必要があります。
- (Android 11 QPR3、Android 11 Car、Android 12)
config_showHeadsUpNotificationOnBottom
: ヘッドアップ通知を上ではなく下に表示するかどうかを表すブール値。この値は、frameworks/base/packages/CarSystemUI/res/values/config.xml
のconfig_showHeadsUpNotificationOnBottom
ブール値リソースと同じにする必要があります。 - (Android 11 QPR3、Android 11 車、Android 12)
notification_headsup_card_margin_horizontal
: ヘッドアップ通知ウィンドウの左右のマージン。この値は、packages/apps/Car/Notification/res/values/dimens.xml
のnotification_headsup_card_margin_horizontal
サイズリソースと同じ値にする必要があります。 - (Android 12)
excluded_application_overlay_window_titles
: オーバーレイ ウィンドウと見なさないウィンドウのタイトルの配列。これには、TaskViews
またはTaskDisplayAreas
を表すアプリ ウィンドウのタイトルを含める必要があります。デフォルトでは、このリストには「マップ」のみが含まれます。
次の RotaryService
リソースをオーバーレイできます。
- (Android 11 QPR3、Android 11 Car、Android 12)
long_press_ms
: 中央ボタンを何ミリ秒押し続けると長押しがトリガーされるかを表す整数値。ゼロは、システムのデフォルトの長押しタイムアウトが使用されることを示し、これがデフォルト値となります。