ปฏิบัติตามคำสั่ง

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

ปฏิบัติตามคำสั่งสื่อ

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

  • แหล่งสื่อภายนอก (เช่น 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 ในรถยนต์บางคัน อาจมีการใช้งานบริการเบราเซอร์สื่อพิเศษบางอย่าง ซึ่งควรยกเว้นไว้ นี่คือตัวอย่างของตรรกะนี้:

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 สำหรับการดำเนินการตามเจตนา ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED และ ACTION_PACKAGE_REMOVED

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

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

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)

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

แฮนด์วิทยุ

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

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

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

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

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

โครงสร้างแผนผังเบราว์เซอร์สื่อที่เกี่ยวข้องถูกกำหนดไว้ที่คลาส BrowserTree คำสั่งควบคุมการเล่นสามารถส่งได้คล้ายกับแอปอื่นๆ โดยใช้การใช้งาน MediaSession

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

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

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

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

ปฏิบัติตามคำสั่งของยานพาหนะ

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

หากต้องการเข้าถึงค่าคงที่เดียวกันเหล่านี้จาก Java คุณสามารถใช้ VehiclePropertyIds และคลาสที่แสดงร่วมได้ คุณสมบัติที่แตกต่างกันมีสิทธิ์ Android ที่แตกต่างกันในการควบคุมการเข้าถึง สิทธิ์เหล่านี้ได้รับการประกาศไว้ใน รายการ CarService และการแมประหว่างคุณสมบัติและการอนุญาตที่อธิบายไว้ใน VehiclePropertyIds Javadoc และบังคับใช้ใน 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 โดยตรงจากรถยนต์หรือผ่าน Bluetooth

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

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

ปฏิบัติตามคำสั่งอื่น ๆ

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

การกระทำที่สมจริง (แสดงเนื้อหาภาพ)

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

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