Bluetooth

Android は、多くの一般的な車載 Bluetooth プロファイルをサポートする完全な Bluetooth 実装を提供します。他のデバイスやサービスのパフォーマンスとエクスペリエンスを向上させる多くの機能強化もあります。

Bluetooth接続管理

Android 内では、 CarBluetoothService が現在のユーザーの Bluetooth デバイスと、IVI への各プロファイル接続の優先リストを維持します。デバイスは、定義された優先順位に従ってプロファイルに接続されます。デバイスをいつ有効化、無効化、プロファイルに接続するかは、必要に応じてリソース オーバーレイを使用して上書きできるデフォルトの接続ポリシーによって決まります。

自動車接続管理の構成

デフォルトの電話ポリシーを無効にする

Android Bluetooth スタックは、デフォルトで有効になっている電話の接続ポリシーを維持します。 CarBluetoothServiceの意図された自動車ポリシーと競合しないように、このポリシーはデバイスで無効にする必要があります。これは Car 製品オーバーレイが自動的に処理しますが、 /packages/apps/Bluetooth/res/values/config.xmlMAXIMUM_CONNECTED_DEVICESenable_phone_policyfalseに設定することで、リソース オーバーレイの電話ポリシーを無効にすることができます。

デフォルトの自動車ポリシーを使用する

CarBluetoothService は、デフォルトのプロファイル権限を維持します。既知のデバイスとそのプロファイルの再接続優先順位のリストはservice/src/com/android/car/BluetoothProfileDeviceManager.javaにあります。

同様に、Bluetooth 接続管理ポリシーはservice/src/com/android/car/BluetoothDeviceConnectionPolicy.javaにあります。デフォルトでは、このポリシーは、Bluetooth がボンディングされたデバイスに接続したり切断したりする必要があるインスタンスを定義します。また、アダプターのオンとオフをいつ行う必要があるかについて、車両固有のケースも管理します。

独自のカスタム自動車接続管理ポリシーを作成する

デフォルトの自動車ポリシーがニーズを満たさない場合は、独自のカスタム ポリシーを優先して無効にすることもできます。カスタム ポリシーは、少なくとも、Bluetooth アダプターをいつ有効または無効にするか、またいつデバイスを接続するかを決定します。さまざまなイベントを使用して、Bluetooth アダプターを有効/無効にしたり、デバイスの接続を開始したりできます。これには、特定の車のプロパティの変更によるイベントも含まれます。

デフォルトの自動車ポリシーを無効にする

まず、カスタム ポリシーを使用するには、リソース オーバーレイuseDefaultBluetoothConnectionPolicyfalseに設定して、デフォルトの自動車ポリシーを無効にする必要があります。このリソースは元々、 packages/services/Car/service/res/values/config.xmlMAXIMUM_CONNECTED_DEVICESの一部として定義されています。

Bluetooth アダプターを有効または無効にする

ポリシーの中核機能の 1 つは、Bluetooth アダプターを適切なタイミングでオンまたはオフにすることです。 BluetoothAdapter.enable()およびBluetoothAdapter.disable()フレームワーク API を使用して、アダプターを有効または無効にできます。これらの呼び出しでは、ユーザーが設定またはその他の手段を通じて選択した永続的な状態が尊重される必要があります。これを行う 1 つの方法は次のとおりです。

/**
 * Turn on the Bluetooth adapter.
 */
private void enableBluetooth() {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        return;
    }
    bluetoothAdapter.enable();
}

/**
 * Turn off the Bluetooth adapter.
 */
private void disableBluetooth() {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        return;
    }
    // Will shut down _without_ persisting the off state as the desired state
    // of the Bluetooth adapter for next start up. This does nothing if the adapter
    // is already off, keeping the existing saved desired state for next reboot.
    bluetoothAdapter.disable(false);
}

Bluetooth アダプターをいつオンまたはオフにするかを決定する

カスタム ポリシーを使用すると、アダプターを有効または無効にする最適なタイミングを示すイベントを自由に決定できます。これを行う方法の 1 つは、 CarPowerManagerで電源状態MAXIMUM_CONNECTED_DEVICESを使用することです。

private final CarPowerStateListenerWithCompletion mCarPowerStateListener =
        new CarPowerStateListenerWithCompletion() {
    @Override
    public void onStateChanged(int state, CompletableFuture<Void> future) {
        if (state == CarPowerManager.CarPowerStateListener.ON) {
            if (isBluetoothPersistedOn()) {
                enableBluetooth();
            }
            return;
        }

        // "Shutdown Prepare" is when the user perceives the car as off
        // This is a good time to turn off Bluetooth
        if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
            disableBluetooth();

            // Let CarPowerManagerService know we're ready to shut down
            if (future != null) {
                future.complete(null);
            }
            return;
        }
    }
};

デバイスをいつ接続するかを決定する

同様に、デバイス接続の開始をトリガーするイベントを決定すると、 CarBluetoothManager は、各 Bluetooth プロファイルに定義された優先順位リストに基づいてデバイスの接続を続行するconnectDevices() API 呼び出しを提供します。

これを実行する必要がある場合の 1 つの例は、Bluetooth アダプターがオンになったときです。

private class BluetoothBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
            if (state == BluetoothAdapter.STATE_ON) {
                // mContext should be your app's context
                Car car = Car.createCar(mContext);
                CarBluetoothManager carBluetoothManager =
                        (CarBluetoothManager) car.getCarManager(Car.BLUETOOTH_SERVICE);
                carBluetoothManager.connectDevices();
            }
        }
    }
}

自動車の接続管理を検証する

接続ポリシーの動作を確認する最も簡単な方法は、IVI で Bluetooth を有効にし、適切な順序で正しいデバイスに自動的に接続されることを検証することです。 Bluetooth アダプターは、設定 UI を使用するか、次の adb コマンドを使用して切り替えることができます。

adb shell su u$(adb shell am get-current-user)_system svc bluetooth disable
adb shell su u$(adb shell am get-current-user)_system svc bluetooth enable

さらに、次のコマンドの出力を使用して、Bluetooth 接続に関連するデバッグ情報を確認できます。

adb shell dumpsys car_service

最後に、独自の自動車ポリシーを構築した場合、カスタム接続動作を検証するには、デバイス接続をトリガーするために選択したイベントを制御する必要があります。

車載用 Bluetooth プロファイル

Android では、IVI は Bluetooth 経由で同時に接続された複数のデバイスをサポートできます。マルチデバイス Bluetooth 電話サービスを使用すると、ユーザーは個人の電話と職場の電話など、別々のデバイスを同時に接続し、どちらのデバイスからでもハンズフリー通話を行うことができます。

接続制限は、通常はプロファイル サービス自体の実装内で、個々の Bluetooth プロファイルによって適用されます。デフォルトでは、 CarBluetoothService は、許可される接続デバイスの最大数についてそれ以上の判断を行いません。

ハンズフリープロファイル

Bluetooth ハンズフリー プロファイル (HFP) を使用すると、車両は接続されたリモート デバイスを介して電話をかけたり受けたりすることができます。各デバイス接続はTelecomManagerに個別の電話アカウントを登録し、利用可能な電話アカウントを IVI アプリにアドバタイズします。

IVI は、HFP 経由で複数のデバイスに接続できます。 HeadsetClientServiceMAX_STATE_MACHINES_POSSIBLE MAXIMUM_CONNECTED_DEVICES 、同時 HFP 接続の最大数を定義します。

ユーザーがデバイスで電話をかけたり受けたりすると、対応する電話アカウントによってHfpClientConnectionオブジェクトが作成されます。 Dialer アプリは、 HfpClientConnectionオブジェクトと対話して、通話の受け入れや切断などの通話機能を管理します。

デフォルトのダイヤラー アプリは、同時に接続された複数の HFP デバイスをサポートしていないことに注意してください。マルチデバイス HFP を実装するには、通話時に使用するデバイス アカウントをユーザーが選択できるようにカスタマイズする必要があります。次に、アプリは正しいアカウントを使用してtelecomManager.placeCallを呼び出します。他のマルチデバイス機能も意図したとおりに動作することを確認する必要があります。

マルチデバイス HFP の検証

マルチデバイス接続が Bluetooth 経由で適切に機能することを確認するには、次の手順を実行します。

  1. Bluetooth を使用してデバイスを IVI に接続し、デバイスからオーディオをストリーミングします。
  2. Bluetooth 経由で 2 台の電話を IVI に接続します。
  3. 電話機を 1 つ選択します。電話機から直接発信することも、IVI を使用して発信することもできます。
    1. どちらの場合も、ストリーミング音声が一時停止し、電話の音声が IVI に接続されたスピーカーで再生されることを確認します。
  4. 同じ電話機を使用して、電話機で直接着信を受信し、IVI を使用して着信を受信します。
    1. どちらの場合も、ストリーミング音声が一時停止し、電話の音声が IVI に接続されたスピーカーで再生されることを確認します。
  5. 接続されている他の電話機で手順 3 と 4 を繰り返します。

緊急通報

緊急電話をかける機能は、車内の電話および Bluetooth 機能の重要な側面です。 IVI から緊急通報を開始するには、次のようなさまざまな方法があります。

  • スタンドアロン eCall ソリューション
  • IVI に統合された eCall ソリューション
  • 内蔵システムが利用できない場合は、接続された Bluetooth 電話に依存する

緊急電話を接続する

eCall 機器は安全性が重要ですが、現在 Android には統合されていません。 ConnectionServiceを使用して、Android を通じて緊急通話機能を公開することができます。これには、緊急通話用のアクセシビリティ オプションが導入されるという利点もあります。詳細については、 「通話アプリの構築」を参照してください。

緊急時のConnectionService を確立する方法の例を次に示します。

public class YourEmergencyConnectionService extends ConnectionService {

    @Override
    public Connection onCreateOutgoingConnection(
            PhoneAccountHandle connectionManagerAccount,
            ConnectionRequest request) {
        // Your equipment specific procedure to make ecall
        // ...
    }

    private void onYourEcallEquipmentReady() {

        PhoneAccountHandle handle =
            new PhoneAccountHandle(new ComponentName(context, YourEmergencyConnectionService),
                    YourEmergencyConnectionId);
        PhoneAccount account =
            new PhoneAccount.Builder(handle, eCallOnlyAccount)
            .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
            .setCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS
                    | PhoneAccount.CAPABILITY_MULTI_USER)
            .build():
        mTelecomManager.registerPhoneAccount(account);
        mTelecomManager.enablePhoneAccount(account.getAccountHandle(), true);
    }
}

緊急通報用に Bluetooth を有効にする

Android 10 より前の緊急通報には、電話から直接ダイヤルし、利用可能な場合は特別な機器を呼び出す必要がありました (たとえば、危険またはユーザーのアクションの検出時の自動トリガー)。 Android 10 以降では、 apps/Bluetooth/res/values/config.xmlMAXIMUM_CONNECTED_DEVICESが設定されている限り、車内のダイヤラーは緊急電話番号に直接電話をかけることができます。

<!-- For supporting emergency call through the hfp client connection service --> <bool name=”hfp_client_connection_service_support_emergency_call”>true</bool>

この方法で緊急通話を実装すると、音声認識などの他のアプリでも緊急電話番号に電話をかけることができます。

電話帳アクセスプロファイル

Bluetooth 電話帳アクセス プロファイル (PBAP) は、接続されたリモート デバイスから連絡先と通話履歴をダウンロードします。 PBAP は、PBAP クライアント ステート マシンによって更新される、集約された検索可能な連絡先リストを維持します。接続された各デバイスは個別の PBAP クライアント ステート マシンと対話し、その結果、通話時に連絡先が適切なデバイスに関連付けられます。

PBAP は単方向であるため、IVI はPbapClientServiceMAXIMUM_CONNECTED_DEVICESへの接続をインスタンス化する必要があり、IVI で許可される同時 PBAP デバイス接続の最大数を定義します。 PBAP クライアントは、接続されている各デバイスの連絡先を連絡先プロバイダーに保存し、アプリからアクセスして各デバイスの電話帳を取得できます。

さらに、接続を確立するには、プロファイル接続が IVI とモバイル デバイスの両方によって承認される必要があります。 PBAP クライアントが切断されると、内部データベースは、以前に接続されていたデバイスに関連付けられたすべての連絡先と通話履歴を削除します。

メッセージアクセスプロファイル

Bluetooth メッセージ アクセス プロファイル (MAP) を使用すると、接続されたリモート デバイスを介して車両が SMS メッセージを送受信できるようになります。現在、メッセージは IVI にローカルに保存されません。代わりに、接続されたリモート デバイスがメッセージを受信するたびに、IVI はメッセージを受信して​​解析し、その内容をインテントインスタンスにブロードキャストし、アプリが受信できるようにします。

メッセージの送受信を目的としてモバイル デバイスに接続するには、IVI は MAP 接続を開始する必要があります。 MapClientServiceMAXIMUM_CONNECTED_DEVICES 、IVI で許可される MAP デバイスの同時接続の最大数を定義します。メッセージを転送するには、その前に各接続が IVI とモバイル デバイスによって承認される必要があります。

高度なオーディオ配信プロファイル

Bluetooth Advanced Audio Distribution Profile (A2DP) を使用すると、車両は接続されたリモート デバイスからオーディオ ストリームを受信できます。

他のプロファイルとは異なり、接続される A2DP デバイスの最大数は、Java ではなくネイティブ スタックで強制されます。この値は現在packages/modules/Bluetooth/system/btif/src/btif_av.cckDefaultMaxConnectedAudioDevices変数を使用して1にハードコーディングされています。

オーディオ/ビデオ リモート コントロール プロファイル

Bluetooth オーディオ/ビデオ リモート コントロール プロファイル (AVRCP) を使用すると、接続されたリモート デバイス上のメディア プレーヤーを車両で制御および閲覧できるようになります。 IVI は AVRCP コントローラーの役割を果たすため、オーディオ再生に影響を与えるトリガーされたコントロールはターゲット デバイスへの A2DP 接続に依存します。

Android 電話上の特定のメディア プレーヤーを AVRCP 経由で IVI で閲覧できるようにするには、電話上のメディア アプリがMediaBrowserServiceを提供し、そのサービスへのcom.android.bluetoothアクセスを許可する必要があります。これを行う方法については、「メディア ブラウザ サービスの構築」で詳しく説明しています。