บลูทูธ

Android มีการใช้งานบลูทูธอย่างเต็มรูปแบบที่รองรับโปรไฟล์บลูทูธในรถยนต์ทั่วไปหลายรายการ นอกจากนี้ยังมีการปรับปรุงอีกมากมายที่ช่วยเพิ่มประสิทธิภาพและประสบการณ์การใช้งานกับอุปกรณ์และบริการอื่นๆ

การจัดการการเชื่อมต่อบลูทูธ

ใน Android นั้น CarBluetoothService จะดูแลอุปกรณ์บลูทูธของผู้ใช้ปัจจุบันและรายการลำดับความสำคัญสำหรับการเชื่อมต่อโปรไฟล์แต่ละรายการกับ IVI อุปกรณ์จะเชื่อมต่อกับโปรไฟล์ตามลําดับความสําคัญที่กําหนด ช่วงเวลาที่จะเปิดใช้ ปิดใช้ และเชื่อมต่ออุปกรณ์กับโปรไฟล์จะขึ้นอยู่กับนโยบายการเชื่อมต่อเริ่มต้นที่ลบล้างได้โดยใช้ การวางซ้อนทรัพยากร หากต้องการ

กำหนดค่าการจัดการการเชื่อมต่อยานยนต์

ปิดใช้นโยบายโทรศัพท์เริ่มต้น

สแต็กบลูทูธของ Android จะรักษานโยบายการเชื่อมต่อสำหรับโทรศัพท์ที่เปิดใช้โดยค่าเริ่มต้น คุณต้องปิดใช้นโยบายนี้ในอุปกรณ์เพื่อไม่ให้ขัดแย้งกับนโยบายยานยนต์ที่ต้องการใน CarBluetoothService แม้ว่าการวางซ้อนผลิตภัณฑ์รถยนต์จะจัดการเรื่องนี้ให้คุณแล้ว แต่คุณก็ปิดใช้นโยบายโทรศัพท์ใน การวางซ้อนทรัพยากรได้โดยตั้งค่า enable_phone_policy เป็น false ใน MAXIMUM_CONNECTED_DEVICES ใน /packages/apps/Bluetooth/res/values/config.xml

ใช้นโยบายยานยนต์เริ่มต้น

CarBluetoothService จะรักษาสิทธิ์โปรไฟล์เริ่มต้นไว้ รายการอุปกรณ์ที่รู้จักและลำดับความสำคัญของการเชื่อมต่อโปรไฟล์อีกครั้งอยู่ในservice/src/com/android/car/BluetoothProfileDeviceManager.java

นอกจากนี้ คุณยังดูนโยบายการจัดการการเชื่อมต่อบลูทูธได้ใน service/src/com/android/car/BluetoothDeviceConnectionPolicy.java โดยค่าเริ่มต้น นโยบายนี้จะกำหนดกรณีที่บลูทูธควรเชื่อมต่อและยกเลิกการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้ รวมถึงจัดการกรณีที่เจาะจงสำหรับรถยนต์ว่าควรเปิดและปิดอะแดปเตอร์เมื่อใด

สร้างนโยบายการจัดการการเชื่อมต่อยานยนต์ที่กำหนดเอง

หากนโยบายยานยนต์เริ่มต้นไม่เพียงพอต่อความต้องการ คุณก็ปิดใช้นโยบายดังกล่าวได้เพื่อใช้นโยบายที่กำหนดเอง นโยบายที่กำหนดเองของคุณจะต้องมีหน้าที่กำหนดอย่างน้อยว่าเมื่อใดควรเปิดและปิดใช้อะแดปเตอร์บลูทูธ รวมถึงกำหนดว่าเมื่อใดควรเชื่อมต่ออุปกรณ์ คุณสามารถใช้เหตุการณ์ต่างๆ เพื่อเปิด/ปิดใช้อะแดปเตอร์บลูทูธและเพื่อเริ่มการเชื่อมต่ออุปกรณ์ รวมถึงเหตุการณ์ที่เกิดจากการเปลี่ยนแปลงในพร็อพเพอร์ตี้บางอย่างของรถ

ปิดใช้นโยบายยานยนต์เริ่มต้น

ก่อนอื่น หากต้องการใช้นโยบายที่กำหนดเอง คุณต้องปิดใช้นโยบายยานยนต์เริ่มต้นโดยตั้งค่า useDefaultBluetoothConnectionPolicy เป็น false ใน การวางซ้อนทรัพยากร ทรัพยากรนี้เดิมกำหนดเป็นส่วนหนึ่งของ MAXIMUM_CONNECTED_DEVICES ใน packages/services/Car/service/res/values/config.xml

เปิดและปิดใช้อะแดปเตอร์บลูทูธ

ฟังก์ชันหลักอย่างหนึ่งของนโยบายคือการเปิดและปิดอะแดปเตอร์บลูทูธในเวลาที่เหมาะสม คุณสามารถใช้ API ของเฟรมเวิร์ก BluetoothAdapter.enable() และ BluetoothAdapter.disable() เพื่อเปิดและปิดใช้อะแดปเตอร์ได้ การเรียกใช้เหล่านี้ควรเป็นไปตามสถานะที่เก็บถาวรซึ่งผู้ใช้เลือกไว้ผ่านการตั้งค่าหรือวิธีอื่นๆ วิธีหนึ่งในการทำเช่นนี้มีดังนี้

/**
 * 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);
}

กำหนดเวลาเปิดและปิดอะแดปเตอร์บลูทูธ

นโยบายที่กำหนดเองช่วยให้คุณเลือกเหตุการณ์ที่ระบุเวลาที่ดีที่สุดในการเปิดและปิดใช้อะแดปเตอร์ได้ วิธีหนึ่งในการทำเช่นนี้คือการใช้สถานะพลังงาน MAXIMUM_CONNECTED_DEVICES ใน 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 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 จะให้บริการเรียก 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 app'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) ของบลูทูธช่วยให้ยานพาหนะโทรออกและรับสายโทรศัพท์ผ่านอุปกรณ์ระยะไกลที่เชื่อมต่อได้ การเชื่อมต่ออุปกรณ์แต่ละรายการจะลงทะเบียนบัญชีโทรศัพท์แยกต่างหากกับ TelecomManager ซึ่งจะแสดงบัญชีโทรศัพท์ที่ใช้ได้ทั้งหมดแก่แอป IVI

IVI สามารถเชื่อมต่อกับอุปกรณ์หลายเครื่องผ่าน HFP MAX_STATE_MACHINES_POSSIBLE MAXIMUM_CONNECTED_DEVICES ใน HeadsetClientService กำหนดจำนวนการเชื่อมต่อ HFP สูงสุดพร้อมกัน

เมื่อผู้ใช้โทรออกหรือรับสายจากอุปกรณ์ บัญชีโทรศัพท์ที่เกี่ยวข้องจะสร้างออบเจ็กต์ HfpClientConnection แอปโทรศัพท์โต้ตอบกับออบเจ็กต์ HfpClientConnection เพื่อจัดการฟีเจอร์การโทร เช่น การยอมรับสายหรือวางสาย

โปรดทราบว่าแอปโทรศัพท์เริ่มต้นไม่รองรับอุปกรณ์ HFP ที่เชื่อมต่อพร้อมกันหลายเครื่อง หากต้องการใช้ HFP หลายอุปกรณ์ ต้องมีการปรับแต่งเพื่อให้ผู้ใช้เลือกบัญชีอุปกรณ์ที่จะใช้เมื่อโทรออก จากนั้นแอปจะโทรหา telecomManager.placeCall ด้วยบัญชีที่ถูกต้อง คุณต้องตรวจสอบว่าฟังก์ชันการทำงานแบบหลายอุปกรณ์อื่นๆ ทำงานได้ตามที่ต้องการด้วย

ยืนยัน HFP สำหรับหลายอุปกรณ์

วิธีตรวจสอบว่าการเชื่อมต่อหลายอุปกรณ์ผ่านบลูทูธทำงานอย่างถูกต้อง

  1. ใช้บลูทูธเชื่อมต่ออุปกรณ์กับ IVI และสตรีมเสียงจากอุปกรณ์
  2. เชื่อมต่อโทรศัพท์ 2 เครื่องกับ IVI ผ่านบลูทูธ
  3. เลือกโทรศัพท์ 1 เครื่อง โทรออกโดยตรงจากโทรศัพท์ และโทรออกโดยใช้ IVI
    1. ตรวจสอบว่าเสียงที่สตรีมหยุดชั่วคราวและเสียงของโทรศัพท์เล่นผ่านลำโพงที่เชื่อมต่อ IVI ทั้งสองครั้ง
  4. รับสายเรียกเข้าโดยตรงในโทรศัพท์และรับสายเรียกเข้าโดยใช้ IVI โดยใช้โทรศัพท์เครื่องเดียวกัน
    1. ตรวจสอบว่าเสียงสตรีมมิงหยุดชั่วคราวและเสียงของโทรศัพท์เล่นผ่านลำโพงที่เชื่อมต่อ IVI ทั้งสองครั้ง
  5. ทำซ้ำขั้นตอนที่ 3 และ 4 ด้วยโทรศัพท์เครื่องอื่นที่เชื่อมต่ออยู่

การโทรหาหมายเลขฉุกเฉิน

ความสามารถในการโทรฉุกเฉินเป็นสิ่งสำคัญของฟังก์ชันโทรศัพท์และบลูทูธในรถยนต์ การโทรฉุกเฉินจาก IVI ทำได้หลายวิธี ดังนี้

  • โซลูชัน eCall แบบสแตนด์อโลน
  • โซลูชัน eCall ที่ผสานรวมเข้ากับ IVI
  • การใช้โทรศัพท์ที่เชื่อมต่อบลูทูธเมื่อไม่มีระบบในตัว

เชื่อมต่อการโทรฉุกเฉิน

แม้ว่าอุปกรณ์ 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);
    }
}

เปิดใช้บลูทูธสำหรับการโทรหาหมายเลขฉุกเฉิน

การโทรหาหมายเลขฉุกเฉินก่อน Android 10 เป็นการโทรโดยตรงจากโทรศัพท์และเรียกใช้อุปกรณ์พิเศษ (เช่น ทริกเกอร์อัตโนมัติเมื่อตรวจพบอันตรายหรือการดําเนินการของผู้ใช้) ใน Android 10 ขึ้นไป แป้นโทรศัพท์ในรถจะโทรหาหมายเลขฉุกเฉินได้โดยตรง ในกรณีที่MAXIMUM_CONNECTED_DEVICESใน 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 ต้องสร้างการเชื่อมต่อกับ MAXIMUM_CONNECTED_DEVICES ใน PbapClientService ซึ่งจะกำหนดจำนวนการเชื่อมต่ออุปกรณ์ PBAP สูงสุดที่อนุญาตพร้อมกันกับ IVI ไคลเอ็นต์ PBAP จะจัดเก็บรายชื่อติดต่อของอุปกรณ์ที่เชื่อมต่อแต่ละเครื่องไว้ใน ผู้ให้บริการรายชื่อติดต่อ จากนั้นแอปจะเข้าถึงเพื่อดึงข้อมูลสมุดโทรศัพท์ของอุปกรณ์แต่ละเครื่องได้

นอกจากนี้ ทั้ง IVI และอุปกรณ์เคลื่อนที่ต้องให้สิทธิ์การเชื่อมต่อโปรไฟล์จึงจะเชื่อมต่อได้ เมื่อไคลเอ็นต์ PBAP ตัดการเชื่อมต่อ ฐานข้อมูลภายในจะนำรายชื่อติดต่อและประวัติการโทรทั้งหมดที่เชื่อมโยงกับอุปกรณ์ที่เชื่อมต่อก่อนหน้านี้ออก

โปรไฟล์การเข้าถึงข้อความ

โปรไฟล์การเข้าถึงข้อความ (MAP) ของบลูทูธช่วยให้ยานพาหนะสามารถส่งและรับข้อความ SMS ผ่านอุปกรณ์ระยะไกลที่เชื่อมต่อ ปัจจุบันระบบไม่ได้จัดเก็บข้อความไว้ใน IVI แต่ทุกครั้งที่อุปกรณ์ระยะไกลที่เชื่อมต่ออยู่ได้รับข้อความ IVI จะรับและแยกวิเคราะห์ข้อความนั้น แล้วออกอากาศเนื้อหาในอินสแตนซ์ Intent ซึ่งแอปจะรับได้

IVI ต้องเริ่มการเชื่อมต่อ MAP เพื่อเชื่อมต่อกับอุปกรณ์เคลื่อนที่เพื่อส่งและรับข้อความ MAXIMUM_CONNECTED_DEVICES ใน MapClientService กำหนดจำนวนการเชื่อมต่ออุปกรณ์ MAP สูงสุดที่อนุญาตพร้อมกันกับ IVI IVI และอุปกรณ์เคลื่อนที่ต้องให้สิทธิ์การเชื่อมต่อแต่ละรายการก่อนจึงจะโอนข้อความได้

Advanced Audio Distribution Profile

โปรไฟล์การกระจายเสียงขั้นสูง (A2DP) ของบลูทูธช่วยให้รถยนต์รับสตรีมเสียงจากอุปกรณ์ระยะไกลที่เชื่อมต่อได้

ซึ่งแตกต่างจากโปรไฟล์อื่นๆ เนื่องจากระบบจะบังคับใช้จำนวนอุปกรณ์ A2DP ที่เชื่อมต่อได้สูงสุดในสแต็กเนทีฟ ไม่ใช่ใน Java ปัจจุบันค่านี้ได้รับการกำหนดค่าแบบฮาร์ดโค้ดเป็น 1 โดยใช้ตัวแปร kDefaultMaxConnectedAudioDevices ใน packages/modules/Bluetooth/system/btif/src/btif_av.cc

โปรไฟล์การควบคุมอุปกรณ์เสียง/วิดีโอจากระยะไกล

โปรไฟล์ควบคุมเสียง/วิดีโอระยะไกล (AVRCP) ของบลูทูธช่วยให้รถควบคุมและเรียกดูโปรแกรมเล่นสื่อในอุปกรณ์ระยะไกลที่เชื่อมต่อได้ เนื่องจาก IVI ทำหน้าที่เป็นตัวควบคุม AVRCP การควบคุมที่ทริกเกอร์ซึ่งส่งผลต่อการเล่นเสียงจึงต้องใช้การเชื่อมต่อ A2DP กับอุปกรณ์เป้าหมาย

หากต้องการให้ IVI เรียกดูโปรแกรมเล่นสื่อที่เฉพาะเจาะจงในโทรศัพท์ Android ผ่าน AVRCP ได้ แอปสื่อในโทรศัพท์ต้องระบุ MediaBrowserService และอนุญาตให้ com.android.bluetooth เข้าถึงบริการนั้น การสร้างบริการเบราว์เซอร์สื่อจะอธิบายวิธีการนี้โดยละเอียด