دستورات را انجام دهید

این صفحه نحوه انجام دستورات با تعامل صوتی را شرح می‌دهد.

دستورات رسانه‌ای را اجرا کنید

دستورات مربوط به رسانه را می‌توان به سه گروه مختلف تقسیم کرد:

  • منابع رسانه خارجی (مانند Spotify نصب شده در AAOS).
  • منابع رسانه‌ای پشتیبان (مانند موسیقی پخش‌شده از طریق VIA).
  • منابع رسانه‌ای محلی (مانند رادیو ماشین).

مدیریت دستورات منبع رسانه خارجی

منابع رسانه خارجی به عنوان برنامه‌های اندرویدی تعریف می‌شوند که از APIهای MediaSessionCompat و MediaBrowseCompat پشتیبانی می‌کنند (برای توضیح دقیق در مورد استفاده از این 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 متدهایی را برای دریافت منبع رسانه‌ای انتخاب‌شده‌ی فعلی و زمان تغییر این منبع رسانه ارائه می‌دهد. این تغییرات می‌تواند به این دلیل رخ دهد که کاربر مستقیماً با رابط کاربری تعامل داشته است یا به دلیل استفاده از دکمه‌های سخت‌افزاری در خودرو. از سوی دیگر، کتابخانه‌ی 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 از قراردادهای خاصی برای سازماندهی اطلاعات و دستورات رسانه‌ای خود استفاده می‌کنند.

رادیو هندل

سرویس MediaBrowse رادیو را می‌توان با فیلتر هدف ACTION_PLAY_BROADCASTRADIO شناسایی کرد. انتظار می‌رود که آنها از کنترل‌های پخش و ساختار مرور رسانه که در Implement radio توضیح داده شده است، پیروی کنند. AAOS کتابخانه car-broadcastradio-support را ارائه می‌دهد که شامل ثابت‌ها و روش‌هایی است که به OEMها کمک می‌کند تا پیاده‌سازی‌های MediaBrowseService را برای سرویس‌های رادیویی خود که از پروتکل تعریف‌شده پیروی می‌کنند، ایجاد کنند و از برنامه‌هایی که از درخت مرور آنها استفاده می‌کنند (به عنوان مثال، VIAها) پشتیبانی می‌کند.

ورودی کمکی، صدای CD و رسانه USB را مدیریت کنید

هیچ پیاده‌سازی پیش‌فرضی از این منابع رسانه‌ای به عنوان بخشی از AOSP وجود ندارد. رویکرد پیشنهادی این است که:

  • از تولیدکنندگان اصلی تجهیزات (OEM) بخواهید سرویس‌های رسانه‌ای را برای هر یک از آنها پیاده‌سازی کنند. برای جزئیات بیشتر، به «ساخت برنامه‌های رسانه‌ای برای خودروها» مراجعه کنید.
  • این پیاده‌سازی‌های MediaBrowseService در اقدامات intent تعریف‌شده در General play intents شناسایی و پاسخ داده می‌شوند.
  • این سرویس‌ها یک درخت مرور را مطابق دستورالعمل‌های شرح داده شده در سایر انواع منبع ، نمایش می‌دهند.

بلوتوث را مدیریت کنید

محتوای رسانه بلوتوث از طریق پروفایل بلوتوث AVRCP در دسترس قرار می‌گیرد. به منظور تسهیل دسترسی به این قابلیت، AAOS شامل پیاده‌سازی MediaBrowserService و MediaSession است که جزئیات ارتباط را خلاصه می‌کند (به packages/apps/Bluetooth مراجعه کنید).

ساختار درختی مرورگر رسانه مربوطه در کلاس BrowseTree تعریف شده است. دستورات کنترل پخش را می‌توان مشابه هر برنامه دیگری، با استفاده از پیاده‌سازی MediaSession، ارائه داد.

مدیریت دستورات مربوط به رسانه‌های استریمینگ

برای پیاده‌سازی پخش رسانه‌ای سمت سرور، VIA باید خود به یک منبع رسانه تبدیل شود و MediaBrowse و MediaSession API را پیاده‌سازی کند. به بخش ساخت برنامه‌های رسانه‌ای برای خودروها مراجعه کنید. با پیاده‌سازی این APIها، یک برنامه کنترل صوتی قادر خواهد بود (از جمله موارد دیگر):

  • به طور یکپارچه در انتخاب منبع رسانه شرکت کنید
  • پس از روشن شدن مجدد خودرو، به طور خودکار از سر گرفته شود
  • کنترل پخش و مرور را با استفاده از رابط کاربری Media Center فراهم کنید
  • دریافت رویدادهای استاندارد دکمه رسانه سخت‌افزاری

هیچ روش استانداردی برای تعامل با همه برنامه‌های ناوبری وجود ندارد. برای ادغام با نقشه‌های گوگل، به Google Maps for Android Automotive Intents مراجعه کنید. برای ادغام با سایر برنامه‌ها، مستقیماً با توسعه‌دهندگان برنامه تماس بگیرید. قبل از اجرای یک intent برای هر برنامه‌ای (از جمله نقشه‌های گوگل)، تأیید کنید که intent قابل حل است (به Google Maps Intents مراجعه کنید). این امر فرصتی را ایجاد می‌کند تا در صورت عدم دسترسی به برنامه هدف، به کاربر اطلاع داده شود.

انجام دستورات مربوط به وسیله نقلیه

دسترسی به ویژگی‌های خودرو برای خواندن و نوشتن از طریق CarPropertyManager فراهم می‌شود. انواع ویژگی‌های خودرو، پیاده‌سازی آن و سایر جزئیات در تنظیمات ویژگی توضیح داده شده است. برای شرح دقیق ویژگی‌های پشتیبانی شده توسط اندروید، بهتر است مستقیماً به hardware/interfaces/automotive/vehicle/2.0/types.hal مراجعه کنید. enum VehicleProperty که در آنجا تعریف شده است شامل ویژگی‌های استاندارد و خاص فروشنده، انواع داده، حالت تغییر، واحدها و تعریف دسترسی خواندن/نوشتن است.

برای دسترسی به همین ثابت‌ها از جاوا، می‌توانید از VehiclePropertyIds و کلاس‌های همراه آن استفاده کنید. ویژگی‌های مختلف، مجوزهای اندروید متفاوتی دارند که دسترسی آنها را کنترل می‌کند. این مجوزها در 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"));
    }

    …
}

انجام دستورات ارتباطی

مدیریت دستورات پیام رسانی

دستیارهای صوتی باید پیام‌های دریافتی را طبق جریان «ضربه زدن برای خواندن» که در دستیار صوتی Tap-to-Read شرح داده شده است، مدیریت کنند، که می‌تواند به صورت اختیاری ارسال پاسخ به فرستنده پیام دریافتی را نیز مدیریت کند. علاوه بر این، VIAها می‌توانند از SmsManager (بخشی از بسته android.telephony ) برای نوشتن و ارسال پیام‌های کوتاه (SMS) مستقیماً از ماشین یا از طریق بلوتوث استفاده کنند.

مدیریت دستورات فراخوانی

به طور مشابه، VIAها می‌توانند TelephonyManager برای برقراری تماس تلفنی و تماس با شماره صندوق صوتی کاربر استفاده کنند. در این موارد، VIAها مستقیماً با پشته تلفن یا با برنامه Car Dialer تعامل خواهند داشت. در هر صورت، برنامه Car Dialer باید رابط کاربری مربوط به تماس صوتی را به کاربر نمایش دهد.

انجام دستورات دیگر

برای فهرستی از سایر نقاط ممکن برای ادغام بین VIA و سیستم، فهرست intent های شناخته شده اندروید را بررسی کنید. بسیاری از دستورات کاربر می‌توانند در سمت سرور حل شوند (به عنوان مثال، خواندن ایمیل‌های کاربران و رویدادهای تقویم) و به هیچ تعاملی با سیستم به جز خود تعامل صوتی نیاز ندارند.

اقدامات همه‌جانبه (نمایش محتوای بصری)

در مواردی که VIA اقدامات یا درک کاربر را بهبود می‌بخشد، می‌تواند محتوای بصری تکمیلی را روی صفحه نمایش خودرو ارائه دهد. برای به حداقل رساندن حواس‌پرتی راننده، چنین محتوایی را ساده، مختصر و قابل اجرا نگه دارید. برای جزئیات بیشتر در مورد دستورالعمل‌های UI/UX در مورد اقدامات فراگیر، به Preloaded Assistants: UX Guidance مراجعه کنید.

برای فعال کردن سفارشی‌سازی و سازگاری با بقیه طراحی واحد اصلی (HU)، VIAها باید از اجزای کتابخانه رابط کاربری خودرو برای اکثر عناصر رابط کاربری استفاده کنند. برای جزئیات بیشتر، به سفارشی‌سازی مراجعه کنید.