블루투스

Android는 일반적인 차량 내 블루투스 프로필 다수를 지원하는 전체 블루투스 구현 기능을 제공합니다. 다른 기기와 서비스의 성능과 사용 환경에 도움이 되는 여러 개선사항도 제공합니다.

블루투스 연결 관리

Android 내에서 CarBluetoothService는 IVI에 연결된 각 프로필의 현재 사용자 블루투스 기기 및 우선순위 목록을 유지합니다. 기기는 정의된 우선순위 순서로 프로필에 연결됩니다. 사용 설정/중지하거나 프로필에 기기를 연결할 때는 기본 연결 정책을 따릅니다. 이 정책은 필요한 경우 리소스 오버레이를 사용하여 재정의할 수 있습니다.

자동차 연결 관리 구성

기본 휴대전화 정책 사용 중지

Android 블루투스 스택은 기본적으로 사용 설정된 휴대전화의 연결 정책을 유지합니다. 이 정책은 CarBluetoothService에서 사용하는 자동차 정책과 충돌하지 않도록 기기에서는 사용 중지해야 합니다. 이러한 사항은 자동차 제품 오버레이에서 처리되긴 하지만, 개발자가 /packages/apps/Bluetooth/res/values/config.xml에서 enable_phone_policyfalse로 설정하여 리소스 오버레이에서 휴대전화 정책을 사용 중지할 수도 있습니다.

기본 자동차 정책 사용

CarBluetoothService는 기본 프로필 권한을 유지합니다. 알려진 기기 및 알려진 기기의 프로필 재연결 우선순위 목록은 service/src/com/android/car/BluetoothProfileDeviceManager.java에 있습니다.

또한 블루투스 연결 관리 정책은 service/src/com/android/car/BluetoothDeviceConnectionPolicy.java에서도 확인할 수 있습니다. 기본적으로 이 정책은 연결된 기기에 블루투스를 연결하거나 연결 해제해야 하는 인스턴스를 정의합니다. 또한 자동차별로 어댑터를 켜거나 꺼야 하는 상황을 관리합니다.

자체적인 자동차 연결 관리 맞춤 정책 만들기

기본 자동차 정책이 원하는 바를 충족시키지 못한다면 사용 중지하고 자체 맞춤 정책을 사용할 수 있습니다. 맞춤 정책에 따라 블루투스 어댑터를 사용 설정하거나 중지할 시점, 기기를 연결하는 시점이 정해집니다. 특정 자동차 속성 변경으로 인한 이벤트와 같은 다양한 이벤트를 사용하여 블루투스 어댑터를 사용 설정/중지하고 기기 연결을 시작할 수 있습니다.

기본 자동차 정책 사용 중지

먼저, 맞춤 정책을 사용하려면 리소스 오버레이에서 useDefaultBluetoothConnectionPolicyfalse로 설정하여 기본 자동차 정책을 사용 중지해야 합니다. 이 리소스는 원래 packages/services/Car/service/res/values/config.xml의 일부로 정의됩니다.

블루투스 어댑터 사용 설정 및 중지

정책의 핵심 기능 중 하나는 적절한 시점에 블루투스 어댑터를 켜고 끄는 것입니다. BluetoothAdapter.enable()BluetoothAdapter.disable() 프레임워크 API를 사용하여 어댑터를 사용 설정하거나 중지할 수 있습니다. 이러한 API 호출은 사용자가 설정이나 다른 방법을 통해 선택한 유지 상태를 존중해야 합니다. 이 작업을 실행하는 방법 중 하나는 다음과 같습니다.

/**
 * 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 will do nothing if the adapter
    // is already off, keeping the existing saved desired state for next reboot.
    bluetoothAdapter.disable(false);
}

블루투스 어댑터를 켜고 끄는 시기 결정

맞춤 정책을 사용하면 어댑터를 사용 설정하고 중지하는 데 가장 적합한 시간을 나타내는 이벤트를 자유롭게 정할 수 있습니다. 이벤트를 결정하는 방법의 하나는 CarPowerManager에서 유지 관리하는 전원 상태를 사용하는 것입니다.

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 will perceive 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에서 각 블루투스 프로필에 정의된 우선순위 목록에 따라 기기 연결을 진행할 connectDevices() API 호출을 제공합니다.

이 작업이 필요한 경우의 예시로는 블루투스 어댑터가 켜질 때를 들 수 있습니다.

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 application’s context
                Car car = Car.createCar(mContext);
                CarBluetoothManager carBluetoothManager =
                        (CarBluetoothManager) car.getCarManager(Car.BLUETOOTH_SERVICE);
                carBluetoothManager.connectDevices();
            }
        }
    }
}

자동차 연결 관리 확인

연결 정책의 동작을 확인하는 가장 쉬운 방법은 IVI에서 블루투스를 사용 설정하고 적절한 순서로 적절한 기기에 자동 연결되는지 확인하는 것입니다. 설정 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

또한 다음 명령어의 출력을 사용하여 블루투스 연결과 관련된 디버깅 정보를 확인할 수 있습니다.

adb shell dumpsys car_service

마지막으로, 자체 자동차 정책을 만든 경우 맞춤 연결 동작을 확인하려면 기기 연결을 트리거하도록 선택한 이벤트를 제어해야 합니다.

자동차 블루투스 프로필

Android에서 IVI는 블루투스를 통해 동시에 여러 기기가 연결되는 것을 지원할 수 있습니다. 다중 기기 블루투스 휴대전화 서비스를 사용하면 사용자가 여러 기기(예: 개인 휴대전화 및 직장 전화)를 동시에 연결하고 어느 기기에서든 핸즈프리 통화를 할 수 있습니다.

연결 제한은 일반적으로 프로필 서비스 자체 구현 내의 개별 블루투스 프로필에서 적용합니다. 기본적으로 CarBluetoothService에서는 허용되는 최대 연결 기기 수에 관해 추가로 판단하지 않습니다.

핸즈프리 프로필

블루투스 핸즈프리 프로필(HFP)을 사용하면 차량이 연결된 원격 기기를 통해 전화를 걸고 받을 수 있습니다. 각 기기 연결은 사용할 수 있는 휴대전화 계정을 IVI 앱에 알려주는 TelecomManager를 사용하여 별도의 휴대전화 계정을 등록합니다.

IVI는 HFP를 통해 여러 기기에 연결할 수 있습니다. HeadsetClientServiceMAX_STATE_MACHINES_POSSIBLE은 동시에 연결할 수 있는 최대 HFP 수를 정의합니다.

사용자가 기기에서 전화를 걸거나 받으면 이에 대응되는 전화 계정에서 HfpClientConnection 객체를 만듭니다. 다이얼러 앱은 HfpClientConnection 객체와 상호작용하여 통화 기능(예: 통화 수락, 통화 끊기)을 관리합니다.

기본 다이얼러 앱은 동시에 여러 HFP 기기 연결을 지원하지 않는다는 점에 유의하세요. 다중 기기 HFP를 구현하려면 전화를 걸 때 사용할 기기 계정을 사용자가 선택하도록 할 수 있는 맞춤설정이 필요합니다. 그러면 앱은 올바른 계정으로 telecomManager.placeCall을 호출합니다. 다른 다중 기기 기능도 정상적으로 작동하는지 확인해야 합니다.

다중 기기 HFP 확인

블루투스를 통해 다중 기기 연결이 제대로 작동하는지 확인하는 방법은 다음과 같습니다.

  1. 블루투스를 사용하여 기기를 IVI에 연결하고 기기에서 오디오를 스트림합니다.
  2. 블루투스를 통해 휴대전화 두 대를 IVI에 연결합니다.
  3. 휴대전화 한 대를 선택합니다. 휴대전화에서 직접 전화를 걸고 IVI를 사용하여 전화를 겁니다.
    1. 두 번 모두 스트림된 오디오가 일시중지되고 IVI 연결 스피커로 휴대전화 오디오가 재생되는지 확인합니다.
  4. 동일한 휴대전화를 사용하여 휴대전화에서 직접 수신 전화를 받고 IVI를 사용하여 수신 전화를 받습니다.
    1. 두 번 모두 스트리밍 오디오가 일시중지되고 IVI 연결 스피커로 휴대전화 오디오가 재생되는지 확인합니다.
  5. 연결된 다른 휴대전화에서 3단계와 4단계를 반복합니다.

긴급 전화

긴급 전화를 거는 기능은 자동차 내 전화와 블루투스 기능에 있어서 중요한 요소입니다. IVI에서 긴급 전화를 시작하는 방법은 다음과 같이 여러 가지가 있습니다.

  • 독립형 eCall 솔루션
  • IVI에 통합된 eCall 솔루션
  • 내장 시스템을 사용할 수 없을 때 연결된 블루투스 휴대전화 사용

긴급 전화 연결

안전에 있어 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.registerPhoneAcccount(account);
        mTelecomManager.enablePhoneAccount(account.getAccountHandle(), true);
    }
}

긴급 전화용 블루투스 사용 설정

Android 10 이전의 긴급 전화에서는 가능한 경우(예: 위험 또는 사용자 작업 감지 시 자동 트리거) 휴대전화에서 직접 전화를 걸고 특별한 장비를 호출했습니다. Android 10 이후에는 긴급 전화번호가 apps/Bluetooth/res/values/config.xml에 포함된 경우 자동차의 다이얼러에서 직접 전화를 걸 수 있습니다.

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

이 방법으로 긴급 전화를 구현하면 음성 인식과 같은 다른 앱에서도 긴급 전화번호로 전화를 걸 수 있습니다.

전화번호부 액세스 프로필

블루투스 전화번호부 액세스 프로필(PBAP)은 연결된 원격 기기에서 연락처 및 통화 기록을 다운로드합니다. PBAP는 PBAP 클라이언트 상태 시스템에서 업데이트하는 연락처의 검색 가능한 집계 목록을 유지합니다. 연결된 각 기기는 별도의 PBAP 클라이언트 상태 시스템과 상호작용하여 전화를 걸 때 연락처가 적절한 기기에 연결됩니다.

PBAP는 단방향이므로 IVI에서 원하는 휴대기기에 연결을 인스턴스화해야 합니다. PbapClientServiceMAXIMUM_DEVICES는 IVI에서 허용하는 최대 PBAP 기기 동시 연결 수를 정의합니다. PBAP 클라이언트에서는 연락처 제공자에 연결된 각 기기의 연락처를 저장하여 애플리케이션에서 각 기기의 전화번호부를 가져올 수 있도록 합니다.

또한, 연결하려면 IVI와 휴대기기 양쪽에서 프로필 연결을 승인해야 합니다. PBAP 클라이언트에서 연결을 끊으면 내부 데이터베이스는 이전에 연결된 기기와 관련된 모든 연락처 및 통화 기록을 삭제합니다.

메시지 액세스 프로필

블루투스 메시지 액세스 프로필(MAP)을 사용하면 차량에서 연결된 원격 기기를 통해 SMS 메시지를 주고받을 수 있습니다. 현재, 메시지는 IVI에 로컬로 저장되지 않습니다. 그 대신 연결된 원격 기기에서 메시지를 수신할 때마다 IVI가 메시지를 수신하여 파싱한 후 애플리케이션에서 수신할 수 있는 인텐트에 이 콘텐츠를 브로드캐스트합니다.

메시지를 주고받기 위해 휴대기기에 연결하려면 IVI에서 MAP 연결을 시작해야 합니다. MapClientServiceMAXIMUM_CONNECTED_DEVICES는 IVI에서 허용하는 최대 MAP 기기 동시 연결 수를 정의합니다. 각 연결은 IVI 및 휴대기기의 승인을 받아야 메시지를 전송할 수 있습니다.

고급 오디오 배포 프로필

블루투스 고급 오디오 배포 프로필(A2DP)을 사용하면 연결된 원격 기기의 오디오 스트림을 차량에서 수신할 수 있습니다.

다른 프로필과 달리, 연결된 A2DP 기기의 최대 수는 자바 스택이 아닌 네이티브 스택에 적용됩니다. 값은 현재 packages/modules/Bluetooth/system/btif/src/btif_av.cckDefaultMaxConnectedAudioDevices 변수를 사용하여 1로 하드코딩되어 있습니다.

오디오/동영상 리모컨 프로필

블루투스 오디오/동영상 리모컨 프로필(AVRCP)을 사용하면 차량에서 연결된 원격 기기의 미디어 플레이어를 제어하고 탐색할 수 있습니다. IVI에서 AVRCP 컨트롤러 역할을 하므로, 오디오 재생에 영향을 미치는 트리거 컨트롤은 대상 기기와의 A2DP 연결을 사용합니다.

IVI에서 AVRCP를 통해 Android 휴대전화의 특정 미디어 플레이어를 탐색할 수 있게 하려면 휴대전화의 미디어 애플리케이션에서 MediaBrowserService를 제공하고 com.android.bluetooth가 서비스에 액세스하도록 허용해야 합니다. 자세한 방법은 미디어 브라우저 서비스 빌드를 참고하세요.