自動車向け Android アプリ ライブラリを使用すると、ナビゲーション、スポット(POI)、モノのインターネット(IOT)アプリを自動車に導入できます。これは、ドライバーの注意散漫に関する基準を満たすように設計された一連のテンプレートを提供し、さまざまな車載画面要素や入力モダリティなどの詳細を処理することで実現されています。
このガイドでは、ライブラリの主な機能とコンセプトの概要を説明し、基本的なアプリを設定するプロセスについて説明します。
始める前に
- 自動車向けアプリ ライブラリに関する運転用のデザインのページを確認します。
- ナビゲーション アプリとその他の運転関連アプリのカテゴリの概要
- テンプレートを使用してアプリを構築するの概要
- テンプレートとテンプレート コンポーネントをカバーする構成要素
- 一般的な UX パターンを示すサンプルフロー
- テンプレート化されたアプリの要件
- 次のセクションの主な用語とコンセプトを確認してください。
- Android Auto システム UI と Android Automotive OS の設計について十分に理解してください。
- リリースノートを確認してください。
- サンプルを確認してください。
主な用語と概念
- モデルとテンプレート
- ユーザー インターフェースは、モデル オブジェクトのグラフで表現され、オブジェクトが属するテンプレートで許可されているように、さまざまな方法で配置できます。テンプレートは、これらのグラフでルートとして機能するモデルのサブセットです。モデルには、テキストや画像の形式でユーザーに表示する情報のほか、情報の外観を構成する属性(テキストの色や画像サイズなど)が含まれます。ホストは、ドライバーの注意散漫基準を満たすように設計されたビューにモデルを変換し、さまざまな車載画面の要素や入力モダリティなどの詳細を処理します。
- ホスト
- ホストは、ライブラリの API が提供する機能を実装するバックエンド コンポーネントです。これにより、アプリを車内で実行できるようになります。ホストの役割は、アプリの検出とそのライフサイクルの管理から、モデルのビューへの変換、アプリへのユーザー操作の通知まで、多岐にわたります。モバイル デバイスでは、このホストは Android Auto によって実装されます。Android Automotive OS では、このホストはシステムアプリとしてインストールされます。
- テンプレートの制限事項
- テンプレートに応じて、そのモデルのコンテンツに制限が課されます。たとえば、リスト テンプレートでは、ユーザーに提示できるアイテム数に上限があります。テンプレートには、タスクのフローを形成するための接続方法にも制限があります。たとえば、画面スタックにプッシュできるテンプレートは 5 つまでです。詳しくは、テンプレートの制限をご覧ください。
Screen
Screen
は、ユーザーに提示されるユーザー インターフェースを管理するためにアプリが実装するライブラリによって提供されるクラスです。Screen
にはライフサイクルがあり、画面が表示されているときに表示するテンプレートをアプリから送信するためのメカニズムを提供します。Screen
インスタンスは、Screen
スタックとの間で push およびポップできるため、テンプレート フローの制限を遵守できます。CarAppService
CarAppService
はService
抽象クラスです。ホストから検出および管理するには、アプリに実装してエクスポートする必要があります。アプリのCarAppService
は、createHostValidator
を使用してホスト接続が信頼できるかどうかを検証し、その後、onCreateSession
を使用して接続ごとにSession
インスタンスを提供します。Session
Session
は抽象クラスであり、アプリはCarAppService.onCreateSession
を使用して実装し、返す必要があります。車の画面に情報を表示するためのエントリ ポイントとして機能します。アプリに表示 / 非表示のタイミングなど、車載画面上のアプリの現在の状態を通知するライフサイクルがあります。アプリの初回起動時など、
Session
が開始されると、ホストはonCreateScreen
メソッドを使用して、最初のScreen
を表示するようリクエストします。
自動車向けアプリ ライブラリをインストールする
アプリにライブラリを追加する手順については、Jetpack ライブラリのリリースページをご覧ください。
アプリのマニフェスト ファイルを構成する
自動車アプリを作成する前に、アプリのマニフェスト ファイルを次のように構成します。
CarAppService を宣言する
ホストは CarAppService
実装を介してアプリに接続します。ホストがアプリを検出して接続できるように、マニフェストでこのサービスを宣言します。
また、アプリのインテント フィルタの <category>
要素でアプリのカテゴリを宣言する必要もあります。この要素に指定できる値については、サポートされているアプリのカテゴリのリストをご覧ください。
次のコード スニペットは、マニフェストでスポットアプリ用の自動車向けアプリサービスを宣言する方法を示しています。
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.POI"/>
</intent-filter>
</service>
...
<application>
サポートされているアプリのカテゴリ
前のセクションで説明したように、CarAppService
を宣言する際に、インテント フィルタに以下のカテゴリ値を 1 つ以上追加して、アプリのカテゴリを宣言します。
androidx.car.app.category.NAVIGATION
: ターンバイターンのルート案内を提供するアプリ。 このカテゴリに関するその他のドキュメントについては、自動車向けナビゲーション アプリを作成するをご覧ください。androidx.car.app.category.POI
: 駐車場、充電スタンド、ガソリン スタンドなどのスポットの検索に関連する機能を提供するアプリ。このカテゴリに関する追加ドキュメントについては、自動車向けスポットアプリを作成するをご覧ください。androidx.car.app.category.IOT
: ユーザーが接続済みデバイスに対して車内から操作できるアプリ。このカテゴリに関する追加ドキュメントについては、自動車向けモノのインターネット アプリを作成するをご覧ください。
各カテゴリの詳細とアプリが分類される条件については、自動車向け Android アプリの品質をご覧ください。
アプリの名前とアイコンを指定する
ホストがシステム UI でアプリを表すために使用するアプリ名とアイコンを指定する必要があります。
CarAppService
の label
属性と icon
属性を使用して、アプリを表すために使用するアプリ名とアイコンを指定できます。
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
<service>
要素でラベルまたはアイコンが宣言されていない場合、ホストは <application>
要素に指定された値にフォールバックします。
カスタムテーマを設定する
自動車向けアプリのカスタムテーマを設定するには、次のようにマニフェスト ファイルに <meta-data>
要素を追加します。
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
次に、スタイル リソースを宣言して、カスタム自動車アプリのテーマに次の属性を設定します。
<resources> <style name="MyCarAppTheme"> <item name="carColorPrimary">@layout/my_primary_car_color</item> <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item> <item name="carColorSecondary">@layout/my_secondary_car_color</item> <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
自動車向けアプリの API レベル
自動車向けアプリ ライブラリは独自の API レベルを定義するため、車両のテンプレート ホストでサポートされているライブラリ機能を確認できます。ホストでサポートされている自動車向けアプリの最も高い API レベルを取得するには、getCarAppApiLevel()
メソッドを使用します。
アプリがサポートする自動車向けアプリの最小 API レベルを AndroidManifest.xml
ファイルで宣言します。
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
下位互換性を維持し、機能の使用に必要な最小 API レベルを宣言する方法については、RequiresCarApi
アノテーションのドキュメントをご覧ください。自動車向けアプリ ライブラリの特定の機能を使用するために必要な API レベルの定義については、CarAppApiLevels
のリファレンス ドキュメントをご覧ください。
CarAppService とセッションを作成する
アプリは CarAppService
クラスを拡張し、その onCreateSession
メソッドを実装する必要があります。このメソッドは、ホストへの現在の接続に対応する Session
インスタンスを返します。
Kotlin
class HelloWorldService : CarAppService() { ... override fun onCreateSession(): Session { return HelloWorldSession() } ... }
Java
public final class HelloWorldService extends CarAppService { ... @Override @NonNull public Session onCreateSession() { return new HelloWorldSession(); } ... }
Session
インスタンスは、アプリの初回起動時に使用する Screen
インスタンスを返します。
Kotlin
class HelloWorldSession : Session() { ... override fun onCreateScreen(intent: Intent): Screen { return HelloWorldScreen(carContext) } ... }
Java
public final class HelloWorldSession extends Session { ... @Override @NonNull public Screen onCreateScreen(@NonNull Intent intent) { return new HelloWorldScreen(getCarContext()); } ... }
ディープリンクの処理など、自動車向けアプリがアプリのホーム画面やランディング 画面ではない画面から起動する必要があるシナリオを処理するには、onCreateScreen
から戻る前に、ScreenManager.push
を使用して画面のバックスタックをプリシードできます。事前に埋め込むことで、ユーザーはアプリによって表示された最初の画面から前の画面に戻ることができます。
起動画面を作成する
アプリに表示される画面を作成するには、Screen
クラスを拡張するクラスを定義し、その onGetTemplate
メソッドを実装します。このメソッドは、車載画面に表示される UI の状態を表す Template
インスタンスを返します。
次のスニペットは、PaneTemplate
テンプレートを使用して単純な「Hello world!」文字列を表示する Screen
を宣言する方法を示しています。
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
CarContext クラス
CarContext
クラスは、Session
インスタンスと Screen
インスタンスからアクセスできる ContextWrapper
サブクラスです。画面スタックを管理するための ScreenManager
、一般的なアプリ関連機能(地図の描画用の Surface
オブジェクトへのアクセスなど)のための自動車サービスへのアクセスを提供します。また、NavigationManager
ターンバイターン ナビゲーション アプリがナビゲーション メタデータやその他のナビゲーション イベントを伝達するために使用する AppManager
ナビゲーション アプリで使用できるライブラリ機能の包括的なリストについては、ナビゲーション テンプレートにアクセスするをご覧ください。
CarContext
はその他の機能も提供します。たとえば、車載画面の構成を使用してドローアブル リソースを読み込む、インテントを使用して車内でアプリを起動する、アプリがダークモードで地図を表示するかどうかのシグナルなどがあります。
画面ナビゲーションを実装する
多くの場合、アプリはさまざまな画面を表示します。各画面では、画面に表示されているインターフェースを操作する際にユーザーが移動する可能性のあるさまざまなテンプレートが使用される場合があります。
ScreenManager
クラスは、ユーザーが車の画面で [戻る] ボタンを選択したとき、または一部の自動車で利用可能なハードウェアの [戻る] ボタンを使用した場合に自動的にポップできる画面をプッシュするために使用できる画面スタックを提供します。
次のスニペットは、「戻る」アクションと、ユーザーが選択したときに新しい画面をプッシュするアクションを追加する方法を示しています。
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
Action.BACK
オブジェクトは、自動的に ScreenManager.pop
を呼び出す標準的な Action
です。この動作は、CarContext
から利用できる OnBackPressedDispatcher
インスタンスを使用することでオーバーライドできます。
運転中にアプリを安全に使用できるようにするため、画面スタックは最大 5 画面まで表示できます。詳しくは、テンプレートの制限のセクションをご覧ください。
テンプレートのコンテンツを更新する
アプリは Screen.invalidate
メソッドを呼び出すことで、Screen
のコンテンツを無効にするようリクエストできます。その後、ホストはアプリの Screen.onGetTemplate
メソッドにコールバックして、新しいコンテンツを含むテンプレートを取得します。
Screen
を更新するときは、ホストが新しいテンプレートをテンプレートの割り当てにカウントしないように、更新可能なテンプレート内の具体的なコンテンツを把握することが重要です。詳しくは、テンプレートの制限をご覧ください。
画面を構成する際は、Screen
と onGetTemplate
実装を通じて返されるテンプレートのタイプが 1 対 1 で対応するように画面を構成することをおすすめします。
地図を描画する
次のテンプレートを使用するナビゲーション アプリとスポット(POI)アプリでは、Surface
にアクセスして地図を描画できます。
Template | テンプレートの権限 | カテゴリに関するガイダンス |
---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
ナビゲーション |
MapWithContentTemplate |
androidx.car.app.NAVIGATION_TEMPLATES または androidx.car.app.MAP_TEMPLATES |
ナビゲーション、スポット |
MapTemplate (非推奨) |
androidx.car.app.NAVIGATION_TEMPLATES |
ナビゲーション |
PlaceListNavigationTemplate (非推奨) |
androidx.car.app.NAVIGATION_TEMPLATES |
ナビゲーション |
RoutePreviewNavigationTemplate (非推奨) |
androidx.car.app.NAVIGATION_TEMPLATES |
ナビゲーション |
サーフェスの権限を宣言する
アプリがサーフェスにアクセスするには、使用するテンプレートに必要な権限に加えて、AndroidManifest.xml
ファイルで androidx.car.app.ACCESS_SURFACE
権限を宣言する必要があります。
<manifest ...>
...
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
...
</manifest>
サーフェスにアクセス
ホストが提供する Surface
にアクセスするには、SurfaceCallback
を実装し、その実装を AppManager
自動車サービスに提供する必要があります。現在の Surface
は、onSurfaceAvailable()
コールバックと onSurfaceDestroyed()
コールバックの SurfaceContainer
パラメータで SurfaceCallback
に渡されます。
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
サーフェスの可視領域について
ホストはテンプレートのユーザー インターフェース要素を地図上に描画できます。ホストは、SurfaceCallback.onVisibleAreaChanged
メソッドを呼び出して、遮られずユーザーに完全に表示されることが保証されているサーフェスの領域を伝えます。また、変更回数を最小限に抑えるために、ホストは SurfaceCallback.onStableAreaChanged
メソッドを呼び出します。この呼び出しでは現在のテンプレートに基づいて常に表示される最小の長方形が使用されます。
たとえば、ナビゲーション アプリがNavigationTemplate
上部にアクション ストリップがある場合、ユーザーが画面をしばらく操作していないと、アクション ストリップ自体を非表示にして、地図のスペースを増やすことができます。この場合、onStableAreaChanged
と onVisibleAreaChanged
へのコールバックがあり、同じ長方形が使用されます。アクション ストリップが非表示の場合は、onVisibleAreaChanged
のみが大きな領域で呼び出されます。ユーザーが画面を操作すると、最初の長方形で onVisibleAreaChanged
のみが再び呼び出されます。
ダークモードをサポートする
条件が満たされているとホストが判断した場合、アプリは適切なダークカラーで Surface
インスタンスに地図を再描画する必要があります。詳しくは、自動車向け Android アプリの品質をご覧ください。
暗い色の地図を描画するかどうかの判断には、CarContext.isDarkMode
メソッドを使用できます。ダークモードのステータスが変わるたびに、Session.onCarConfigurationChanged
の呼び出しを受け取ります。
ユーザーが地図を操作できるようにする
次のテンプレートを使用すると、ズームやパンによって地図のさまざまな部分をユーザーに表示するなど、ユーザーが描画した地図を操作できるようになります。
Template | インタラクティビティをサポートする Car App API レベル |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (非推奨) |
4 |
RoutePreviewNavigationTemplate (非推奨) |
4 |
MapTemplate (非推奨) |
5(テンプレートの導入) |
MapWithContentTemplate |
7(テンプレートの導入) |
インタラクティビティ コールバックを実装する
SurfaceCallback
インターフェースには、前のセクションのテンプレートで作成した地図にインタラクティビティを追加するために実装できるコールバック メソッドがいくつかあります。
操作 | SurfaceCallback メソッド |
サポートする Car App API レベル |
---|---|---|
タップ | onClick |
5 |
ピンチしてズーム | onScale |
2 |
シングルタップ ドラッグ | onScroll |
2 |
シングルタップ フリング | onFling |
2 |
ダブルタップ | onScale (スケール ファクタはテンプレート ホストによって決まります) |
2 |
パンモードの回転ナッジ | onScroll (距離係数はテンプレート ホストによって決まります) |
2 |
地図アクション ストリップを追加する
これらのテンプレートには、地図に関連する操作(ズームインとズームアウト、センタリング、コンパスの表示、その他の表示アクションなど)の地図アクション ストリップを含めることができます。地図アクション ストリップには、タスクの深さに影響を与えることなく更新できる、アイコンのみのボタンを 4 つまで設定できます。アイドル状態では非表示になり、アクティブ状態では再表示されます。
地図のインタラクティビティ コールバックを受け取るには、地図のアクション ストリップに Action.PAN
ボタンを追加する必要があります。ユーザーがパンボタンを押すと、次のセクションで説明するように、ホストはパンモードになります。
アプリのマップ アクション ストリップに Action.PAN
ボタンを設定しない場合、SurfaceCallback
メソッドからユーザー入力を取得できず、ホストで有効になっていたパンモードが終了します。
パンボタンはタッチスクリーンには表示されません。
パンモードについて
パンモードでは、ノンタッチの入力デバイス(ロータリー コントローラやタッチパッドなど)からのユーザー入力が、テンプレート ホストによって適切な SurfaceCallback
メソッドに変換されます。パンモードを開始または終了するユーザー操作には、NavigationTemplate.Builder
の setPanModeListener
メソッドで応答します。ユーザーがパンモードのときは、テンプレートの他の UI コンポーネントを非表示にできます。
ユーザーとやり取りする
アプリは、モバイルアプリと同様のパターンを使用してユーザーとやり取りできます。
ユーザー入力を処理する
アプリは、適切なリスナーをそれらをサポートするモデルに渡すことで、ユーザー入力に応答できます。次のスニペットは、アプリのコードで定義されたメソッドにコールバックする OnClickListener
を設定する Action
モデルの作成方法を示しています。
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
その後、onClickNavigate
メソッドで CarContext.startCarApp
メソッドを使用して、デフォルトのナビゲーション自動車アプリを起動できます。
Kotlin
private fun onClickNavigate() { val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)) carContext.startCarApp(intent) }
Java
private void onClickNavigate() { Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)); getCarContext().startCarApp(intent); }
ACTION_NAVIGATE
インテントの形式など、アプリの起動方法について詳しくは、インテントを使用して自動車アプリを起動するをご覧ください。
インタラクションの続きをモバイル デバイスで行うようにユーザーをガイドするアクションなど、特定のアクションは車がパーキング状態にあるときに限り許可されます。これらのアクションは、ParkedOnlyOnClickListener
を使用して実装できます。車が駐車されていない場合、ホストはユーザーに対してアクションが許可されていないことを示します。車が駐車している場合、コードは通常どおり実行されます。次のスニペットは、ParkedOnlyOnClickListener
を使用してモバイル デバイスで設定画面を開く方法を示しています。
Kotlin
val row = Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone)) .build()
Java
Row row = new Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)) .build();
通知を表示する
モバイル デバイスに送信された通知は、CarAppExtender
で拡張された場合にのみ、車の画面に表示されます。コンテンツのタイトル、テキスト、アイコン、アクションなど、一部の通知属性は CarAppExtender
で設定できます。この属性は、車の画面に表示されたときに通知の属性をオーバーライドします。
次のスニペットは、モバイル デバイスとは異なるタイトルで、通知を車の画面に送信する方法を示しています。
Kotlin
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build()
Java
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( new CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build();
通知は、ユーザー インターフェースの次の部分に影響する場合があります。
- ヘッドアップ通知(HUN)がユーザーに表示されることがあります。
- 通知センターにエントリが追加されたり、必要に応じて、レールにバッジが表示されたりすることがあります。
- ナビゲーション アプリの場合、ターンバイターン通知で説明されているように、通知はレール ウィジェットに表示されることがあります。
CarAppExtender
のドキュメントで説明されているように、通知の優先度を使用して、これらの各ユーザー インターフェース要素に影響するようにアプリの通知を設定する方法を選択できます。
true
の値で NotificationCompat.Builder.setOnlyAlertOnce
が呼び出された場合、優先度の高い通知は HUN として 1 回だけ表示されます。
自動車向けアプリの通知の設計方法については、Google Design for Driving ガイドの通知をご覧ください。
トーストを表示する
次のスニペットに示すように、アプリでは CarToast
を使用してトーストを表示できます。
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
権限をリクエストする
位置情報などの制限付きデータやアクションにアプリがアクセスする必要がある場合は、Android 権限の標準ルールが適用されます。権限をリクエストするには、CarContext.requestPermissions()
メソッドを使用します。
標準の Android API ではなく、CarContext.requestPermissions()
を使用する利点は、権限ダイアログを作成するために独自の Activity
を起動する必要がないことです。さらに、Android Auto と Android Automotive OS の両方で同じコードを使用できます。プラットフォームに依存するフローを作成する必要はありません。
Android Auto の権限ダイアログのスタイルを設定する
Android Auto では、ユーザーの権限ダイアログがスマートフォンに表示されます。デフォルトでは、ダイアログの背景は表示されません。カスタム背景を設定するには、AndroidManifest.xml
ファイルで自動車向けアプリのテーマを宣言し、自動車向けアプリのテーマの carPermissionActivityLayout
属性を設定します。
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
次に、自動車向けアプリのテーマの carPermissionActivityLayout
属性を設定します。
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
インテントを使用して自動車アプリを起動する
CarContext.startCarApp
メソッドを呼び出して、次のいずれかのアクションを実行できます。
- 電話アプリを開いて電話をかける。
- デフォルトのナビゲーション自動車アプリを使用して、場所へのターンバイターン方式のナビを開始する。
- インテントを使用して独自のアプリを起動する。
次の例は、駐車予約の詳細を表示する画面でアプリを開く、というアクションを含む通知を作成する方法を示しています。アプリのアクションに対する明示的インテントをラップする PendingIntent
を含むコンテンツ インテントを使用して、通知インスタンスを拡張します。
Kotlin
val notification = notificationBuilder ... .extend( CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(ComponentName(context, MyNotificationReceiver::class.java)), 0)) .build())
Java
Notification notification = notificationBuilder ... .extend( new CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), new Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(new ComponentName(context, MyNotificationReceiver.class)), 0)) .build());
また、ユーザーが通知インターフェースでアクションを選択し、データ URI を含むインテントで CarContext.startCarApp
を呼び出したときに呼び出される BroadcastReceiver
も宣言する必要があります。
Kotlin
class MyNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val intentAction = intent.action if (ACTION_VIEW_PARKING_RESERVATION == intentAction) { CarContext.startCarApp( intent, Intent(Intent.ACTION_VIEW) .setComponent(ComponentName(context, MyCarAppService::class.java)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))) } } }
Java
public class MyNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) { CarContext.startCarApp( intent, new Intent(Intent.ACTION_VIEW) .setComponent(new ComponentName(context, MyCarAppService.class)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))); } } }
最後に、アプリの Session.onNewIntent
メソッドが、駐車予約画面がまだ一番上にない場合に、その画面をスタックにプッシュして、このインテントを処理します。
Kotlin
override fun onNewIntent(intent: Intent) { val screenManager = carContext.getCarService(ScreenManager::class.java) val uri = intent.data if (uri != null && MY_URI_SCHEME == uri.scheme && MY_URI_HOST == uri.schemeSpecificPart && ACTION_VIEW_PARKING_RESERVATION == uri.fragment ) { val top = screenManager.top if (top !is ParkingReservationScreen) { screenManager.push(ParkingReservationScreen(carContext)) } } }
Java
@Override public void onNewIntent(@NonNull Intent intent) { ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class); Uri uri = intent.getData(); if (uri != null && MY_URI_SCHEME.equals(uri.getScheme()) && MY_URI_HOST.equals(uri.getSchemeSpecificPart()) && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment()) ) { Screen top = screenManager.getTop(); if (!(top instanceof ParkingReservationScreen)) { screenManager.push(new ParkingReservationScreen(getCarContext())); } } }
自動車アプリの通知を処理する方法について詳しくは、通知を表示するのセクションをご覧ください。
テンプレートの制限事項
ホストは、特定のタスクに対して表示するテンプレートの数を最大 5 つに制限します。最後のテンプレートは、次のいずれかのタイプである必要があります。
この上限はテンプレートの数に適用されます。スタック内の Screen
インスタンスの数には適用されません。たとえば、アプリが画面 A で 2 つのテンプレートを送信してから画面 B をプッシュした場合、さらに 3 つのテンプレートを送信できるようになります。また、各画面が 1 つのテンプレートを送信するように構成されている場合、アプリは 5 つの画面インスタンスを ScreenManager
スタックにプッシュできます。
これらの制限には、テンプレートの更新や、「戻る」操作とリセット操作などの特殊なケースがあります。
テンプレートの更新
一部のコンテンツの更新は、テンプレートの制限にカウントされません。一般的に、アプリがプッシュする新しいテンプレートの種類が以前のテンプレートと同じメイン コンテンツである場合、その新しいテンプレートは割り当てにカウントされません。たとえば、ListTemplate
内で行の切り替え状態を更新しても、割り当てに対するカウントは行われません。どのような種類のコンテンツ更新がテンプレートの更新としてカウントされるかについて詳しくは、個々のテンプレートのドキュメントをご覧ください。
戻る操作
タスク内でサブフローを有効にするために、ホストは、アプリが ScreenManager
スタックから Screen
をポップするタイミングを検出し、アプリが戻るテンプレートの数に基づいて残りの割り当てを更新します。
たとえば、アプリが画面 A で 2 つのテンプレートを送信し、画面 B をプッシュしてさらに 2 つのテンプレートを送信した場合、アプリの割り当ては 1 つになります。その後アプリがポップバックして画面 A に戻った場合、アプリはテンプレートを 2 つ戻ったため、ホストは割り当てを 3 にリセットします。
画面にポップバックする場合、アプリはその画面で最後に送信されたテンプレートと同じタイプのテンプレートを送信する必要があります。他のテンプレート タイプを送信するとエラーが発生します。ただし、戻る操作時にタイプが同じのままであれば、アプリは割り当てに影響を与えることなくテンプレートのコンテンツを自由に変更できます。
リセット操作
一部のテンプレートには、タスクの終了を示す特別なセマンティクスがあります。たとえば、NavigationTemplate
は、画面に表示され続け、ユーザーが消費できるように新しいターンバイターンの指示で更新されることが想定されるビューです。これらのテンプレートのいずれかに達すると、ホストはテンプレートの割り当てをリセットし、そのテンプレートを新しいタスクの最初のステップのように扱います。これにより、アプリは新しいタスクを開始できるようになります。ホスト上でリセットがトリガーされるテンプレートについては、個々のテンプレートのドキュメントをご覧ください。
ホストが通知アクションまたはランチャーからアプリを起動するインテントを受け取ると、割り当てもリセットされます。このメカニズムにより、アプリは通知から新しいタスクフローを開始できます。このメカニズムは、アプリがすでにバインドされていてフォアグラウンドで実行されている場合でも変わりません。
アプリの通知を車の画面に表示する方法について詳しくは、通知を表示するのセクションをご覧ください。通知アクションからアプリを起動する方法については、インテントを使用して自動車用アプリを起動するをご覧ください。
接続 API
アプリが Android Auto と Android Automotive OS のどちらで実行されているかを確認するには、CarConnection
API を使用して実行時に接続情報を取得します。
たとえば、自動車アプリの Session
で、CarConnection
を初期化し、LiveData
の更新にサブスクライブします。
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
オブザーバーで、接続状態の変化に対応できます。
Kotlin
fun onConnectionStateUpdated(connectionState: Int) { val message = when(connectionState) { CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS" CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" else -> "Unknown car connection type" } CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show() }
Java
private void onConnectionStateUpdated(int connectionState) { String message; switch(connectionState) { case CarConnection.CONNECTION_TYPE_NOT_CONNECTED: message = "Not connected to a head unit"; break; case CarConnection.CONNECTION_TYPE_NATIVE: message = "Connected to Android Automotive OS"; break; case CarConnection.CONNECTION_TYPE_PROJECTION: message = "Connected to Android Auto"; break; default: message = "Unknown car connection type"; break; } CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show(); }
制約 API
車によって、ユーザーに一度に表示される Item
インスタンスの数が異なる場合があります。ConstraintManager
を使用して実行時にコンテンツの上限を確認し、テンプレートに適切な数のアイテムを設定します。
まず、CarContext
から ConstraintManager
を取得します。
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
次に、取得した ConstraintManager
オブジェクトにクエリを実行して、関連するコンテンツの上限を取得します。たとえば、グリッドに表示できるアイテム数を取得するには、CONTENT_LIMIT_TYPE_GRID
を指定して getContentLimit
を呼び出します。
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
ログインフローを追加する
アプリでユーザーにログイン エクスペリエンスを提供する場合は、Car App API レベル 2 以上で SignInTemplate
や LongMessageTemplate
などのテンプレートを使用して、車のヘッドユニットでアプリへのログインを処理できます。
SignInTemplate
を作成するには、SignInMethod
を定義します。自動車向けアプリ ライブラリは現在、次のログイン方法をサポートしています。
- ユーザー名/パスワードによるログイン用の
InputSignInMethod
。 - PIN ログイン用の
PinSignInMethod
。ユーザーは、ヘッドユニットに表示された PIN を使用してスマートフォンからアカウントをリンクします。 - プロバイダ ログイン用の
ProviderSignInMethod
(Google ログインやワンタップなど)。 QRCodeSignInMethod
: QR コード ログイン用。ユーザーが QR コードをスキャンしてスマートフォンでログインを完了します。これは、Car API レベル 4 以降で使用できます。
たとえば、ユーザーのパスワードを収集するテンプレートを実装するには、まず InputCallback
を作成してユーザー入力の処理と検証を行います。
Kotlin
val callback = object : InputCallback { override fun onInputSubmitted(text: String) { // You will receive this callback when the user presses Enter on the keyboard. } override fun onInputTextChanged(text: String) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } }
Java
InputCallback callback = new InputCallback() { @Override public void onInputSubmitted(@NonNull String text) { // You will receive this callback when the user presses Enter on the keyboard. } @Override public void onInputTextChanged(@NonNull String text) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } };
InputSignInMethod
Builder
には InputCallback
が必要です。
Kotlin
val passwordInput = InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build()
Java
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build();
最後に、新しい InputSignInMethod
を使用して SignInTemplate
を作成します。
Kotlin
SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build()
Java
new SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build();
AccountManager を使用する
認証が必要な Android Automotive OS アプリでは、次の理由により AccountManager を使用する必要があります。
- UX の向上とアカウント管理の容易さ: ユーザーは、ログインやログアウトを含むシステム設定のアカウント メニューから、すべてのアカウントを簡単に管理できます。
- 「ゲスト」エクスペリエンス: 自動車は共有デバイスであるため、OEM は車両でのゲスト エクスペリエンスを有効にできます。ただし、アカウントを追加することはできません。
テキスト文字列のバリエーションを追加する
自動車の画面サイズに応じて、表示されるテキストの量は異なります。自動車向けアプリの API レベル 2 以上では、画面に合う最適なテキスト文字列のバリエーションを複数指定できます。テキストのバリエーションを使用できる場所を確認するには、CarText
を使用するテンプレートとコンポーネントを探してください。
テキスト文字列のバリエーションを CarText
に追加するには、CarText.Builder.addVariant()
メソッドを使用します。
Kotlin
val itemTitle = CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build()
Java
CarText itemTitle = new CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build();
この CarText
を、GridItem
のプライマリ テキストなどに使用できます。
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
文字列を優先度の高い順に追加します(たとえば、長い順など)。ホストは、車載画面のスペースの大きさに応じて、適切な長さの文字列を選択します。
行にインライン CarIcons を追加する
CarIconSpan
を使用すると、テキストにアイコンをインラインで追加して、アプリの視覚的な魅力を充実させることができます。これらのスパンの作成の詳細については、CarIconSpan.create
のドキュメントをご覧ください。スパンを使用したテキスト スタイル設定の仕組みの概要については、スパンを使用した空間テキストのスタイル設定をご覧ください。
Kotlin
val rating = SpannableString("Rating: 4.5 stars") rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) val row = Row.Builder() ... .addText(rating) .build()
Java
SpannableString rating = new SpannableString("Rating: 4.5 stars"); rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars new CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ); Row row = new Row.Builder() ... .addText(rating) .build();
自動車ハードウェア API
自動車向けアプリの API レベル 3 以降、自動車向けアプリ ライブラリには、車両のプロパティとセンサーへのアクセスに使用できる API があります。
要件
Android Auto で API を使用するには、まず androidx.car.app:app-projected
への依存関係を Android Auto モジュールの build.gradle
ファイルに追加します。Android Automotive OS の場合は、androidx.car.app:app-automotive
への依存関係を Android Automotive OS モジュールの build.gradle
ファイルに追加します。
また、AndroidManifest.xml
ファイルで、使用する車のデータをリクエストするために必要な関連する権限を宣言する必要があります。これらの権限は、ユーザーから自身に付与される必要があります。プラットフォームに依存するフローを作成しなくても、Android Auto と Android Automotive OS の両方で同じコードを使用できます。ただし、必要な権限は異なります。
自動車情報
次の表に、CarInfo
API によって表示されるプロパティと、それらを使用するためにリクエストする必要がある権限を示します。
メソッド | プロパティ | Android Auto の権限 | Android Automotive OS の権限 | サポートする Car App API レベル |
---|---|---|---|---|
fetchModel |
メーカー、モデル、年 | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
EV コネクタの種類、燃料の種類 | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
このデータは、API 30 以上を搭載した一部の Android Automotive OS 車両でのみ利用可能です |
外装寸法 | なし | android.car.permission.CAR_INFO |
7 |
addTollListener
removeTollListener |
通行料金カードのステータス、通行料金カードの種類 | 3 | ||
addEnergyLevelListener
removeEnergyLevelListener |
バッテリー残量、燃料残量、燃料残量、残量 | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_ENERGY 、android.car.permission.CAR_ENERGY_PORTS 、android.car.permission.READ_CAR_DISPLAY_UNITS
|
3 |
addSpeedListener
removeSpeedListener |
未加工の速度、表示速度(車のクラスタ ディスプレイに表示) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED 、android.car.permission.READ_CAR_DISPLAY_UNITS |
3 |
addMileageListener
removeMileageListener |
走行距離計 | com.google.android.gms.permission.CAR_MILEAGE |
このデータは、Google Play ストアからインストールしたアプリでは Android Automotive OS では利用できません。 | 3 |
たとえば、残りの範囲を取得するには、CarInfo
オブジェクトをインスタンス化し、OnCarDataAvailableListener
を作成して登録します。
Kotlin
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo val listener = OnCarDataAvailableListener<EnergyLevel> { data -> if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) { val rangeRemaining = data.rangeRemainingMeters.value } else { // Handle error } } carInfo.addEnergyLevelListener(carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener)
Java
CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo(); OnCarDataAvailableListener<EnergyLevel> listener = (data) -> { if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) { float rangeRemaining = data.getRangeRemainingMeters().getValue(); } else { // Handle error } }; carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener);
自動車からのデータが常に利用できるとは限りません。エラーが発生した場合は、リクエストした値のステータスを確認して、リクエストしたデータを取得できなかった理由を詳しく調べます。CarInfo
クラスの完全な定義については、リファレンス ドキュメントをご覧ください。
自動車用センサー
CarSensors
クラスを使用すると、車両の加速度計、ジャイロスコープ、コンパス、位置情報のデータにアクセスできます。これらの値を使用できるかどうかは、OEM によって異なります。加速度計、ジャイロスコープ、コンパスからのデータの形式は、SensorManager
API で取得するものと同じです。たとえば、車両の向きを確認するには、次のようにします。
Kotlin
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val listener = OnCarDataAvailableListener<Compass> { data -> if (data.orientations.status == CarValue.STATUS_SUCCESS) { val orientation = data.orientations.value } else { // Data not available, handle error } } carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener)
Java
CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors(); OnCarDataAvailableListener<Compass> listener = (data) -> { if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) { List<Float> orientations = data.getOrientations().getValue(); } else { // Data not available, handle error } }; carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener);
車から位置情報にアクセスするには、android.permission.ACCESS_FINE_LOCATION
権限を宣言してリクエストする必要もあります。
テスト
Android Auto でテストする際にセンサーデータをシミュレートするには、デスクトップ ヘッドユニット ガイドのセンサーとセンサー構成のセクションをご覧ください。Android Automotive OS でテストする際にセンサーデータをシミュレートするには、Android Automotive OS エミュレータ ガイドのハードウェアの状態をエミュレートするをご覧ください。
CarAppService、Session、Screen のライフサイクル
Session
クラスと Screen
クラスは LifecycleOwner
インターフェースを実装します。ユーザーがアプリを操作すると、次の図に示すように、Session
オブジェクトと Screen
オブジェクトのライフサイクル コールバックが呼び出されます。
CarAppService とセッションのライフサイクル
詳細については、Session.getLifecycle
メソッドのドキュメントをご覧ください。
画面のライフサイクル
詳細については、Screen.getLifecycle
メソッドのドキュメントをご覧ください。
車のマイクから録音する
アプリの CarAppService
と CarAudioRecord
API を使用すると、アプリにユーザーの車のマイクへのアクセス権を付与できます。ユーザーは、アプリに車のマイクへのアクセスを許可する必要があります。アプリは、アプリ内のユーザー入力を記録して処理できます。
録音の許可
音声を録音する前に、AndroidManifest.xml
で録音する権限を宣言し、ユーザーにその権限の付与をリクエストする必要があります。
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
録画の権限を実行時にリクエストする必要がある。自動車アプリで権限をリクエストする方法については、権限をリクエストするのセクションをご覧ください。
音声を記録する
ユーザーが録音を許可すると、音声を録音して処理できるようになります。
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) carAudioRecord.startRecording() val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording()
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); carAudioRecord.startRecording(); byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE]; while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording();
音声フォーカス
車のマイクから録音するときは、まず音声フォーカスを取得して、進行中のメディアがすべて停止されるようにします。音声フォーカスが失われた場合は、録音を停止します。
音声フォーカスを取得する方法の例を次に示します。
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) // Take audio focus so that user's media is not recorded val audioAttributes = AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build() val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { state: Int -> if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording() } } .build() if (carContext.getSystemService(AudioManager::class.java) .requestAudioFocus(audioFocusRequest) != AudioManager.AUDIOFOCUS_REQUEST_GRANTED ) { // Don't record if the focus isn't granted return } carAudioRecord.startRecording() // Process the audio and abandon the AudioFocusRequest when done
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); // Take audio focus so that user's media is not recorded AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build(); AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(state -> { if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording(); } }) .build(); if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest) != AUDIOFOCUS_REQUEST_GRANTED) { // Don't record if the focus isn't granted return; } carAudioRecord.startRecording(); // Process the audio and abandon the AudioFocusRequest when done
テスト ライブラリ
自動車向け Android テスト ライブラリには、テスト環境でのアプリの動作の検証に使用できる補助クラスが用意されています。たとえば、SessionController
を使用すると、ホストへの接続をシミュレートして、正しい Screen
と Template
が作成されて返されることを確認できます。
使用例については、サンプルをご覧ください。
自動車向け Android アプリ ライブラリに関する問題を報告する
ライブラリに問題が見つかった場合は、Google Issue Tracker を使用して報告してください。問題テンプレートに必要な情報をすべて記入してください。
新しい問題を報告する前に、その問題がライブラリのリリースノートまたは問題リストで報告されていないかご確認ください。Issue Tracker 内で各問題の横にあるスターアイコンをクリックすると、問題を登録して投票することができます。詳細については、問題を登録する手順をご覧ください。