บลูทูธ

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

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

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

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

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

สแต็กบลูทูธของ Android จะเก็บรักษานโยบายการเชื่อมต่อสำหรับโทรศัพท์ซึ่งเปิดใช้โดย ค่าเริ่มต้น คุณต้องปิดใช้นโยบายนี้ในอุปกรณ์เพื่อไม่ให้นโยบายขัดแย้งกับ นโยบายยานยนต์ที่ต้องการใน CarBluetoothService แม้ว่าการซ้อนทับผลิตภัณฑ์ Car จะจัดการเรื่องนี้ให้คุณ คุณก็สามารถปิดใช้นโยบายโทรศัพท์ในการ ซ้อนทับทรัพยากรได้โดยตั้งค่า 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

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

ฟังก์ชันหลักอย่างหนึ่งของนโยบายคือการเปิดและปิดใช้อแดปเตอร์บลูทูธในเวลาที่เหมาะสม คุณสามารถใช้ BluetoothAdapter.enable() และ BluetoothAdapter.disable() 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 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 ทั้ง 2 ครั้ง
  4. ใช้โทรศัพท์เครื่องเดียวกันเพื่อรับสายเรียกเข้าโดยตรงในโทรศัพท์ และ รับสายเรียกเข้าโดยใช้ IVI
    1. ตรวจสอบว่าเสียงที่สตรีมหยุดชั่วคราวและเสียงโทรศัพท์เล่นผ่านลำโพงที่เชื่อมต่อกับ IVI ทั้ง 2 ครั้ง
  5. ทำซ้ำขั้นตอนที่ 3 และ 4 กับโทรศัพท์เครื่องอื่นที่เชื่อมต่อ

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

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

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

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

แม้ว่าอุปกรณ์ eCall จะมีความสำคัญต่อความปลอดภัย แต่ปัจจุบันอุปกรณ์นี้ยังไม่ได้ผสานรวมกับ Android คุณสามารถใช้ ConnectionService เพื่อแสดงฟีเจอร์การโทรหาหมายเลขฉุกเฉินผ่าน Android ซึ่งมีประโยชน์เพิ่มเติมคือ การนำเสนอตัวเลือกการช่วยเหลือพิเศษสำหรับการโทรหาหมายเลขฉุกเฉิน ดูข้อมูลเพิ่มเติมได้ที่ Building a calling app

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

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

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

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

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

โปรไฟล์การกระจายเสียงขั้นสูง

โปรไฟล์การกระจายเสียงขั้นสูง (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 เข้าถึง บริการดังกล่าว Building a media browser service อธิบายวิธีดำเนินการนี้โดยละเอียด