ดำเนินการตามคําสั่ง

หน้านี้อธิบายวิธีดำเนินการตามคำสั่งด้วยการโต้ตอบด้วยเสียง

ดำเนินการตามคำสั่งเกี่ยวกับสื่อ

คำสั่งที่เกี่ยวข้องกับสื่อสามารถแบ่งออกเป็น 3 กลุ่มที่แตกต่างกัน ดังนี้

  • แหล่งที่มาของสื่อภายนอก (เช่น Spotify ที่ติดตั้งใน AAOS)
  • แหล่งที่มาของสื่อแบ็กเอนด์ (เช่น เพลงที่สตรีมผ่าน VIA)
  • แหล่งที่มาของสื่อในเครื่อง (เช่น วิทยุในรถ)

จัดการคำสั่งแหล่งที่มาของสื่อภายนอก

แหล่งที่มาของสื่อภายนอกกำหนดไว้เป็นแอป Android ที่รองรับ MediaSessionCompat และ MediaBrowseCompat API (ดูคำอธิบายโดยละเอียดเกี่ยวกับการใช้ API เหล่านี้ได้ที่ สร้างแอปสื่อสำหรับ รถยนต์)

สำคัญ: แอปผู้ช่วยต้องมีคุณสมบัติดังต่อไปนี้จึงจะเชื่อมต่อกับ MediaBrowseService ของแอปสื่อทั้งหมดที่ติดตั้งในระบบได้

  1. ติดตั้งเป็นแอปที่ลงชื่อโดยระบบ (ดูหลักเกณฑ์การพัฒนาแอปพลิเคชันสื่อสำหรับ AAOS และโค้ดตัวอย่าง PackageValidator)
  2. มีสิทธิ์ android.permission.MEDIA_CONTENT_CONTROL ที่ได้รับสิทธิ์พิเศษจากระบบ (ดูหัวข้อให้สิทธิ์ ที่ได้รับสิทธิ์พิเศษจากระบบ)

นอกจาก MediaBrowserCompat และ MediaControllerCompat, แล้ว AAOS ยังมีสิ่งต่อไปนี้ด้วย

  • CarMediaService ให้ข้อมูลแบบรวมศูนย์เกี่ยวกับแหล่งที่มาของสื่อที่เลือกในปัจจุบัน นอกจากนี้ยังใช้เพื่อกลับมาเล่นแหล่งที่มาของสื่อที่เล่นก่อนหน้านี้หลังจากปิดและรีสตาร์ทรถ
  • car-media-common มีเมธอดที่สะดวกในการแสดงรายการ เชื่อมต่อ และโต้ตอบกับแอปสื่อ

ด้านล่างนี้คือหลักเกณฑ์เฉพาะสำหรับการใช้คำสั่งการโต้ตอบด้วยเสียงทั่วไป

รับรายการแหล่งที่มาของสื่อที่ติดตั้ง

ระบบจะตรวจหาแหล่งที่มาของสื่อได้โดยใช้ PackageManager, และกรองหาบริการที่ตรงกับ MediaBrowserService.SERVICE_INTERFACE รถบางรุ่นอาจมีการใช้บริการ Media Browser แบบพิเศษ ซึ่งควรยกเว้น ตัวอย่างตรรกะนี้มีดังนี้

private Map<String, MediaSource> getAvailableMediaSources() {
    List<String> customMediaServices =
        Arrays.asList(mContext.getResources()
            .getStringArray(R.array.custom_media_packages));
    List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices(
            new Intent(MediaBrowserService.SERVICE_INTERFACE),
            PackageManager.GET_RESOLVED_FILTER);
    Map<String, MediaSource> result = new HashMap<>();
    for (ResolveInfo info : mediaServices) {
        String packageName = info.serviceInfo.packageName;
        if (customMediaServices.contains(packageName)) {
            // Custom media sources should be ignored, as they might have a
            // specialized handling (e.g., radio).
            continue;
        }
        String className = info.serviceInfo.name;
        ComponentName componentName = new ComponentName(packageName,
            className);
        MediaSource source = MediaSource.create(mContext, componentName);
        result.put(source.getDisplayName().toString().toLowerCase(),
            source);
    }
    return result;
}

โปรดทราบว่าแหล่งที่มาของสื่ออาจมีการติดตั้งหรือถอนการติดตั้งได้ทุกเมื่อ เราขอแนะนำให้ใช้อินสแตนซ์ BroadcastReceiverสำหรับ การดำเนินการ Intent ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED, และ ACTION_PACKAGE_REMOVEDเพื่อให้รายการถูกต้อง

เชื่อมต่อกับแหล่งที่มาของสื่อที่กำลังเล่น

CarMediaService มีเมธอดสำหรับรับแหล่งที่มาของสื่อที่เลือกในปัจจุบัน และเมื่อแหล่งที่มาของสื่อนี้มีการเปลี่ยนแปลง การเปลี่ยนแปลงเหล่านี้อาจเกิดขึ้นเนื่องจากผู้ใช้โต้ตอบกับ UI โดยตรง หรือเนื่องจากการใช้ปุ่มฮาร์ดแวร์ในรถ ในทางกลับกัน ไลบรารี car-media-common มีวิธีที่สะดวกในการเชื่อมต่อกับแหล่งที่มาของสื่อที่กำหนด ต่อไปนี้เป็นข้อมูลโค้ดแบบย่อเกี่ยวกับวิธีเชื่อมต่อกับแอปสื่อที่เลือกในปัจจุบัน

public class MediaActuator implements
        MediaBrowserConnector.onConnectedBrowserChanged {
    private final Car mCar;
    private CarMediaManager mCarMediaManager;
    private MediaBrowserConnector mBrowserConnector;

    

    public void initialize(Context context) {
        mCar = Car.createCar(context);
        mBrowserConnector = new MediaBrowserConnector(context, this);
        mCarMediaManager = (CarMediaManager)
            mCar.getCarManager(Car.CAR_MEDIA_SERVICE);
        mBrowserConnector.connectTo(mCarMediaManager.getMediaSource());
        
    }

    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        // TODO: Handle connected/disconnected browser
    }

    
}

ควบคุมการเล่นแหล่งที่มาของสื่อที่กำลังเล่น

เมื่อเชื่อมต่อ MediaBrowserCompat แล้ว คุณจะส่งคำสั่งควบคุมการขนส่งไปยังแอปเป้าหมายได้อย่างง่ายดาย ตัวอย่างแบบย่อมีดังนี้

public class MediaActuator   {
    
    private MediaControllerCompat mMediaController;

    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        if (browser != null && browser.isConnected()) {
            mMediaController = new MediaControllerCompat(mContext,
                browser.getSessionToken());
        } else {
            mMediaController = null;
        }
    }

    private boolean playSongOnCurrentSource(String song) {
        if (mMediaController == null) {
            // No source selected.
            return false;
        }
        MediaControllerCompat.TransportControls controls =
            mMediaController.getTransportControls();
        PlaybackStateCompat state = controller.getPlaybackState();
        if (state == null || ((state.getActions() &
                PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) {
            // Source can't play from search
            return false;
        }
        controls.playFromSearch(query, null);
        return true;
    }

    
}

จัดการคำสั่งแหล่งที่มาของสื่อในเครื่อง (วิทยุ เครื่องเล่นซีดี บลูทูธ USB)

แหล่งที่มาของสื่อในเครื่องจะแสดงฟังก์ชันการทำงานต่อระบบโดยใช้ API MediaSession และ MediaBrowse เดียวกันกับที่อธิบายไว้ข้างต้น บริการ MediaBrowse เหล่านี้ใช้กฎเฉพาะเพื่อจัดระเบียบข้อมูลและคำสั่งสื่อเพื่อให้สอดคล้องกับลักษณะเฉพาะของฮาร์ดแวร์แต่ละประเภท

จัดการวิทยุ

คุณระบุ Radio MediaBrowseService ได้ด้วยตัวกรอง Intent ACTION_PLAY_BROADCASTRADIO โดยคาดว่าจะปฏิบัติตามการควบคุมการเล่นและโครงสร้างการเรียกดูสื่อ ที่อธิบายไว้ในหัวข้อใช้ฟังก์ชันวิทยุ AAOS มีไลบรารี car-broadcastradio-support ที่มีค่าคงที่และเมธอดเพื่อช่วยให้ OEM สร้างการใช้ MediaBrowseService สำหรับบริการวิทยุของตนเองที่ปฏิบัติตามโปรโตคอลที่กำหนด และรองรับแอปที่ใช้โครงสร้างการเรียกดู (เช่น VIA)

จัดการอินพุตเสริม เสียงจากซีดี และสื่อจาก USB

ไม่มีการใช้แหล่งที่มาของสื่อเหล่านี้เป็นค่าเริ่มต้นใน AOSP แนวทางที่แนะนำมีดังนี้

จัดการบลูทูธ

เนื้อหาสื่อบลูทูธจะแสดงผ่านโปรไฟล์บลูทูธ AVRCP AAOS มีการใช้ MediaBrowserService และ MediaSession ที่สรุปรายละเอียดการสื่อสาร (ดู packages/apps/Bluetooth) เพื่อช่วยให้เข้าถึงฟังก์ชันการทำงานนี้ได้ง่ายขึ้น

โครงสร้างโครงสร้างการเรียกดูสื่อที่เกี่ยวข้องจะกำหนดไว้ที่ BrowseTree คลาส คุณสามารถส่งคำสั่งควบคุมการเล่นได้ในลักษณะเดียวกับแอปอื่นๆ โดยใช้การใช้ MediaSession ของแอป

จัดการคำสั่งสื่อสตรีมมิง

หากต้องการใช้การสตรีมสื่อฝั่งเซิร์ฟเวอร์ VIA ต้องกลายเป็นแหล่งที่มาของสื่อเอง โดยใช้ API MediaBrowse และ MediaSession ดูที่ สร้างแอปสื่อ สำหรับรถยนต์ การใช้ API เหล่านี้จะช่วยให้แอปควบคุมด้วยเสียงทำสิ่งต่อไปนี้ได้ (นอกเหนือจากสิ่งอื่นๆ)

  • เข้าร่วมการเลือกแหล่งที่มาของสื่อได้อย่างราบรื่น
  • กลับมาทำงานต่อโดยอัตโนมัติหลังจากรีสตาร์ทรถ
  • ให้การควบคุมการเล่นและการเรียกดูโดยใช้ UI ของ Media Center
  • รับเหตุการณ์ปุ่มสื่อฮาร์ดแวร์มาตรฐาน

ไม่มีวิธีมาตรฐานในการโต้ตอบกับแอปการนำทางทั้งหมด หากต้องการผสานรวมกับ Google Maps โปรดดู Google Maps สำหรับ Android Automotive Intent หากต้องการผสานรวมกับแอปอื่นๆ โปรดติดต่อนักพัฒนาแอปโดยตรง ก่อนที่จะเปิดใช้ Intent ไปยังแอปใดก็ตาม (รวมถึง Google Maps) ให้ตรวจสอบว่า Intent สามารถ แก้ไขได้ (ดู Intent ของ Google Maps) ซึ่งจะช่วยให้คุณแจ้งให้ผู้ใช้ทราบได้ในกรณีที่แอปเป้าหมายไม่พร้อมใช้งาน

ดำเนินการตามคำสั่งเกี่ยวกับรถ

คุณสามารถเข้าถึงพร็อพเพอร์ตี้ของรถเพื่ออ่านและเขียนได้ผ่าน CarPropertyManager ประเภทพร็อพเพอร์ตี้ของรถ การใช้พร็อพเพอร์ตี้ และรายละเอียดอื่นๆ อธิบายไว้ ใน หัวข้อการกำหนดค่า พร็อพเพอร์ตี้ หากต้องการคำอธิบายที่ถูกต้องเกี่ยวกับพร็อพเพอร์ตี้ที่ Android รองรับ คุณควรดู hardware/interfaces/automotive/vehicle/2.0/types.hal โดยตรง Enum VehicleProperty ที่กำหนดไว้ในนั้นมีทั้งพร็อพเพอร์ตี้มาตรฐานและพร็อพเพอร์ตี้เฉพาะของผู้ให้บริการ, ประเภทข้อมูล, โหมดการเปลี่ยนแปลง, หน่วย และคำจำกัดความการเข้าถึงแบบอ่าน/เขียน

หากต้องการเข้าถึงค่าคงที่เดียวกันนี้จาก Java คุณสามารถใช้ VehiclePropertyIds และคลาสที่เกี่ยวข้อง พร็อพเพอร์ตี้ต่างๆ มีสิทธิ์ของ Android ที่แตกต่างกันในการควบคุมการเข้าถึง สิทธิ์เหล่านี้ประกาศไว้ในไฟล์ Manifest ของ CarService และการแมประหว่างพร็อพเพอร์ตี้กับสิทธิ์อธิบายไว้ ใน Javadoc ของ VehiclePropertyIds และบังคับใช้ใน PropertyHalServiceIds

อ่านพร็อพเพอร์ตี้ของรถ

ตัวอย่างต่อไปนี้แสดงวิธีอ่านความเร็วของรถ

public class CarActuator ... {
    private final Car mCar;
    private final CarPropertyManager mCarPropertyManager;
    private final TextToSpeech mTTS;

    /** Global VHAL area id */
    public static final int GLOBAL_AREA_ID = 0;

    public CarActuator(Context context, TextToSpeech tts) {
        mCar = Car.createCar(context);
        mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
        mTTS = tts;
        ...
    }

    @Nullable
    private void getSpeedInMetersPerSecond() {
        if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED,
                GLOBAL_AREA_ID)) {
            mTTS.speak("I'm sorry, but I can't read the speed of this vehicle");
            return;
        }
        // Data type and unit can be found in
        // automotive/vehicle/2.0/types.hal
        float speedInMps = mCarPropertyManager.getFloatProperty(
                VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID);
        int speedInMph = (int)(speedInMetersPerSecond * 2.23694f);
        mTTS.speak(String.format("Sure. Your current speed is %d miles "
                + "per hour", speedInUserUnit);
    }

    ...
}

ตั้งค่าพร็อพเพอร์ตี้ของรถ

ตัวอย่างต่อไปนี้แสดงวิธีเปิดและปิดเครื่องปรับอากาศด้านหน้า

public class CarActuator … {
    …

    private void changeFrontAC(boolean turnOn) {
        List<CarPropertyConfig> configs = mCarPropertyManager
                .getPropertyList(new ArraySet<>(Arrays.asList(
                    VehiclePropertyIds.HVAC_AC_ON)));
        if (configs == null || configs.size() != 1) {
            mTTS.speak("I'm sorry, but I can't control the AC of your vehicle");
            return;
        }

        // Find the front area Ids for the AC property.
        int[] areaIds = configs.get(0).getAreaIds();
        List<Integer> areasToChange = new ArrayList<>();
        for (int areaId : areaIds) {
            if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER
                        | VehicleAreaSeat.SEAT_ROW_1_LEFT
                        | VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) {
                continue;
            }
            boolean isACInAreaAlreadyOn = mCarPropertyManager
                    .getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId);
            if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) {
                areasToChange.add(areaId);
            }
        }
        if (areasToChange.isEmpty()) {
            mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off"));
            return;
        }

        for (int areaId : areasToChange) {
            mCarPropertyManager.setBooleanProperty(
                VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn);
        }
        mTTS.speak(String.format("Okay, I'm turning your front AC %s",
            turnOn ? "on" : "off"));
    }

    …
}

ดำเนินการตามคำสั่งการสื่อสาร

จัดการคำสั่งการรับส่งข้อความ

VIA ต้องจัดการข้อความขาเข้าตามขั้นตอน "แตะเพื่ออ่าน" ที่อธิบายไว้ ใน ฟีเจอร์แตะเพื่ออ่านของระบบผู้ช่วยแบบเสียง ซึ่งอาจจัดการการส่งคำตอบกลับไปยังผู้ส่งข้อความขาเข้าได้ นอกจากนี้ VIA ยังใช้ SmsManager (ซึ่งเป็นส่วนหนึ่งของแพ็กเกจ android.telephony ) เพื่อเขียนและส่ง SMS โดยตรงจากรถหรือผ่านบลูทูธได้ด้วย

จัดการคำสั่งการโทร

ในลักษณะเดียวกัน VIA สามารถใช้ TelephonyManager เพื่อโทรออกและโทรไปยังหมายเลขวอยซ์เมลของผู้ใช้ได้ ในกรณีเหล่านี้ VIA จะโต้ตอบกับสแต็กโทรคมนาคมโดยตรงหรือกับแอปโทรออกของรถ ในทุกกรณี แอปโทรออกของรถควรเป็นแอปที่แสดง UI ที่เกี่ยวข้องกับการโทรด้วยเสียงต่อผู้ใช้

ดำเนินการตามคำสั่งอื่นๆ

หากต้องการดูรายการจุดผสานรวมอื่นๆ ที่เป็นไปได้ระหว่าง VIA กับ ระบบ โปรดดูรายการ Intent ของ Android ที่รู้จักกันดี คำสั่งของผู้ใช้จำนวนมากสามารถแก้ไขได้ฝั่งเซิร์ฟเวอร์ (เช่น การอ่านอีเมลและกิจกรรมในปฏิทินของผู้ใช้) และไม่จำเป็นต้องมีการโต้ตอบกับระบบนอกเหนือจากการโต้ตอบด้วยเสียง

การดำเนินการแบบเต็มหน้าจอ (แสดงเนื้อหาภาพ)

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

VIA ควรใช้คอมโพเนนต์ของไลบรารี Car UI สำหรับองค์ประกอบ UI ส่วนใหญ่ เพื่อให้ปรับแต่งได้และสอดคล้องกับ การออกแบบส่วนอื่นๆ ของชุดอุปกรณ์บนแผงหน้าปัด (HU) ดูรายละเอียดได้ที่ การปรับแต่ง