تنفيذ الأوامر

توضح هذه الصفحة كيفية تنفيذ الأوامر من خلال التفاعل الصوتي.

تنفيذ أوامر الوسائط

يمكن تقسيم الأوامر المتعلقة بالوسائط إلى ثلاث مجموعات مختلفة:

  • مصادر الوسائط الخارجية (مثل Spotify المثبت في AAOS).
  • مصادر الوسائط الخلفية (مثل الموسيقى المتدفقة عبر VIA).
  • مصادر وسائل الإعلام المحلية (مثل راديو السيارة).

التعامل مع أوامر مصدر الوسائط الخارجية

يتم تعريف مصادر الوسائط الخارجية على أنها تطبيقات Android التي تدعم واجهات برمجة التطبيقات MediaSessionCompat و MediaBrowseCompat (راجع إنشاء تطبيقات الوسائط للسيارات للحصول على شرح تفصيلي حول استخدام واجهات برمجة التطبيقات هذه).

هام: لكي يتصل تطبيق مساعد بخدمة 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;
    }

    …
}

التعامل مع أوامر مصدر الوسائط المحلية (الراديو ومشغل الأقراص المضغوطة وBluetooth وUSB)

تعرض مصادر الوسائط المحلية وظائفها للنظام باستخدام نفس واجهات برمجة تطبيقات MediaSession وMediaBrowse المفصلة أعلاه. لاستيعاب خصوصيات كل نوع من الأجهزة، تستخدم خدمات MediaBrowse هذه اصطلاحات محددة لتنظيم المعلومات وأوامر الوسائط الخاصة بها.

التعامل مع الراديو

يمكن التعرف على Radio MediaBrowseService من خلال مرشح الهدف ACTION_PLAY_BROADCASTRADIO . ومن المتوقع أن يتبعوا عناصر التحكم في التشغيل وبنية تصفح الوسائط الموضحة في تنفيذ الراديو . تقدم AAOS مكتبة car-broadcastradio-support التي تحتوي على ثوابت وطرق لمساعدة مصنعي المعدات الأصلية على إنشاء تطبيقات MediaBrowseService لخدمات الراديو الخاصة بهم التي تتبع البروتوكول المحدد، وتوفر الدعم للتطبيقات التي تستهلك شجرة التصفح الخاصة بهم (على سبيل المثال، VIAs).

التعامل مع الإدخال المساعد، وصوت القرص المضغوط، ووسائط USB

لا يوجد تنفيذ افتراضي لمصادر الوسائط هذه كجزء من AOSP. النهج المقترح هو:

التعامل مع البلوتوث

يتم عرض محتوى وسائط Bluetooth من خلال ملف تعريف AVRCP Bluetooth. لتسهيل الوصول إلى هذه الوظيفة، يتضمن AAOS تطبيق MediaBrowserService وMediaSession الذي يلخص تفاصيل الاتصال (انظر الحزم/التطبيقات/Bluetooth ).

يتم تعريف بنية شجرة متصفح الوسائط المعنية في فئة BrowseTree . يمكن تسليم أوامر التحكم في التشغيل بشكل مشابه لأي تطبيق آخر، وذلك باستخدام تطبيق MediaSession الخاص به.

التعامل مع أوامر الوسائط المتدفقة

لتنفيذ تدفق الوسائط من جانب الخادم، يجب أن تصبح VIA نفسها مصدرًا للوسائط، وتقوم بتنفيذ MediaBrowse وMediaSession API. راجع إنشاء تطبيقات الوسائط للسيارات . من خلال تنفيذ واجهات برمجة التطبيقات هذه، سيكون تطبيق التحكم الصوتي قادرًا على (من بين أشياء أخرى):

  • المشاركة بسلاسة في اختيار مصدر الوسائط
  • يتم استئنافه تلقائيًا بعد إعادة تشغيل السيارة
  • توفير التحكم في التشغيل والتصفح باستخدام Media Center UI
  • تلقي أحداث زر وسائط الأجهزة القياسية

لا توجد طريقة موحدة للتفاعل مع جميع تطبيقات الملاحة. لعمليات التكامل مع خرائط Google، راجع خرائط Google لـ Android Automotive Intents . للتكامل مع التطبيقات الأخرى، اتصل بمطوري التطبيق مباشرة. قبل إطلاق نية لأي تطبيق (بما في ذلك خرائط Google)، تأكد من إمكانية حل النية (راجع طلبات النية ). وهذا يخلق الفرصة لإبلاغ المستخدم في حالة عدم توفر التطبيق المستهدف.

تنفيذ أوامر السيارة

يتم توفير الوصول إلى خصائص السيارة لكل من القراءة والكتابة من خلال 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 وإرسالها مباشرة من السيارة أو عبر البلوتوث.

التعامل مع أوامر الاتصال

وبطريقة مماثلة، يمكن لـ VIAs استخدام TelephonyManager لإجراء مكالمات هاتفية والاتصال برقم البريد الصوتي الخاص بالمستخدم. في هذه الحالات، سوف تتفاعل VIAs مع مجموعة الاتصالات الهاتفية مباشرةً أو مع تطبيق Car Dialer. على أية حال، يجب أن يكون تطبيق Car Dialer هو التطبيق الذي يعرض واجهة المستخدم المتعلقة بالمكالمات الصوتية للمستخدم.

تنفيذ الأوامر الأخرى

للحصول على قائمة بنقاط التكامل المحتملة الأخرى بين VIA والنظام، تحقق من قائمة نوايا Android المعروفة. يمكن حل العديد من أوامر المستخدم من جانب الخادم (على سبيل المثال، قراءة رسائل البريد الإلكتروني للمستخدمين وأحداث التقويم) ولا تتطلب أي تفاعلات مع النظام بخلاف التفاعل الصوتي نفسه.

إجراءات غامرة (عرض المحتوى المرئي)

حيث تعمل على تحسين إجراءات المستخدم أو فهمه، يمكن لـ VIA توفير محتوى مرئي إضافي على شاشة السيارة. لتقليل تشتيت انتباه السائق، اجعل هذا المحتوى بسيطًا ومختصرًا وقابلاً للتنفيذ. للحصول على تفاصيل حول إرشادات واجهة المستخدم/تجربة المستخدم بشأن الإجراءات الغامرة، راجع المساعدين المحملين مسبقًا: إرشادات تجربة المستخدم .

لتمكين التخصيص والاتساق مع بقية تصميم الوحدة الرئيسية (HU)، يجب أن تستخدم VIAs مكونات Car UI Library لمعظم عناصر واجهة المستخدم. للحصول على التفاصيل، راجع التخصيص .