Komutları yerine getirme

Bu sayfada, sesli etkileşimle komutların nasıl yerine getirileceği açıklanmaktadır.

Medya komutlarını yerine getirme

Medya ile ilgili komutlar üç farklı gruba ayrılabilir:

  • Harici medya kaynakları (AAOS'te yüklü Spotify gibi).
  • Arka uç medya kaynakları (ör. VIA üzerinden yayınlanan müzik).
  • Yerel medya kaynakları (araba radyosu gibi).

Harici medya kaynağı komutlarını işleme

Harici medya kaynakları, MediaSessionCompat ve MediaBrowseCompat API'lerini destekleyen Android uygulamaları olarak tanımlanır (bu API'lerin kullanımıyla ilgili ayrıntılı açıklama için Arabalar için medya uygulamaları oluşturma başlıklı makaleyi inceleyin).

Önemli: Bir asistan uygulamasının sistemdeki tüm yüklü medya uygulamalarının MediaBrowseService'sine bağlanması için:

  1. Sistem imzalı olarak yüklenmelidir (AAOS için medya uygulaması geliştirme kurallarına ve örnek PackageValidator koduna bakın).
  2. android.permission.MEDIA_CONTENT_CONTROL sistem ayrıcalıklı iznine sahip olmalıdır (Sistem ayrıcalıklı izin verme bölümüne bakın).

MediaBrowserCompat ve MediaControllerCompat'e ek olarak AOAS aşağıdakileri sağlar:

  • CarMediaService mevcut medya kaynağıyla ilgili merkezi bilgiler sağlar. Bu, araç kapatıldıktan ve yeniden başlatıldıktan sonra daha önce oynatılan bir medya kaynağını devam ettirmek için de kullanılır.
  • car-media-common, medya uygulamalarını listeleme, bağlama ve bunlarla etkileşime geçmeye yönelik kullanışlı yöntemler sunar.

Aşağıda, yaygın sesli etkileşim komutlarının uygulanmasına özel kurallar verilmiştir.

Yüklü medya kaynaklarının listesini alma

Medya kaynakları, PackageManager kullanılarak ve MediaBrowserService.SERVICE_INTERFACE ile eşleşen hizmetler için filtreleme yapılarak algılanabilir. Bazı araçlarda, hariç tutulması gereken özel medya tarayıcısı hizmeti uygulamaları olabilir. Bu mantıkla ilgili bir örnek aşağıda verilmiştir:

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;
}

Medya kaynaklarının dilediğiniz zaman yüklenebileceğini veya kaldırılabileceğini unutmayın. Doğru bir liste tutmak için ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED ve ACTION_PACKAGE_REMOVED intent işlemleri için bir BroadcastReceiver örneği uygulamanız önerilir.

Şu anda çalan medya kaynağına bağlanma

CarMediaService, şu anda seçili olan medya kaynağını ve bu medya kaynağının ne zaman değiştiğini alma yöntemleri sağlar. Bu değişiklikler, kullanıcının doğrudan kullanıcı arayüzüyle etkileşime geçmesi veya araçtaki donanım düğmelerinin kullanılması nedeniyle gerçekleşebilir. Öte yandan, car-media-common kitaplığı belirli bir medya kaynağına bağlanmanın kullanışlı yollarını sunar. Şu anda seçili olan medya uygulamasına nasıl bağlanacağınıza dair basitleştirilmiş bir snippet'i aşağıda bulabilirsiniz:

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
    }

    
}

Şu anda oynatılan medya kaynağının oynatılmasını kontrol etme

Bağlı bir MediaBrowserCompat ile hedef uygulamaya aktarıcı denetim komutları göndermek kolaydır. Aşağıda basitleştirilmiş bir örnek verilmiştir:

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;
    }

    
}

Yerel medya kaynağı komutlarını (radyo, CD çalar, Bluetooth, USB) işleme

Yerel medya kaynakları, yukarıda açıklanan MediaSession ve MediaBrowse API'lerini kullanarak işlevlerini sisteme gösterir. Bu MediaBrowse hizmetleri, her donanım türünün özelliklerine uyum sağlamak için bilgilerini ve medya komutlarını düzenlemek üzere belirli kurallar kullanır.

Radyoyla ilgili işlemler

Radyo MediaBrowseService, ACTION_PLAY_BROADCASTRADIO intent filtresiyle tanımlanabilir. Radyo uygulama bölümünde açıklanan oynatma kontrollerini ve medya tarama yapısını uygulamaları beklenir. AAOS, OEM'lerin kendi radyo hizmetleri için tanımlanmış protokole uyan MediaBrowseService uygulamaları oluşturmasına yardımcı olacak sabitler ve yöntemler içeren car-broadcastradio-support kitaplığını sunar ve tarama ağaçlarını kullanan uygulamalara (ör. VIA'lar) destek sağlar.

Yardımcı giriş, CD sesi ve USB medyasını işleme

AOSP kapsamında bu medya kaynaklarının varsayılan bir uygulaması yoktur. Önerilen yaklaşım şudur:

Bluetooth'u kullanma

Bluetooth medya içeriği, AVRCP Bluetooth profili aracılığıyla gösterilir. Bu işleve erişimi kolaylaştırmak için AAOS, iletişim ayrıntılarını soyutlayan bir MediaBrowserService ve MediaSession uygulaması içerir (packages/apps/Bluetooth bölümüne bakın).

İlgili medya tarayıcısı ağaç yapısı, BrowseTree sınıfında tanımlanır. Oynatma kontrol komutları, MediaSession uygulaması kullanılarak diğer uygulamalara benzer şekilde gönderilebilir.

Medya aktarma komutlarını işleme

Sunucu tarafı medya aktarımını uygulamak için VIA'nın, MediaBrowse ve MediaSession API'yi uygulayarak bir medya kaynağı haline gelmesi gerekir. Arabalar için medya uygulamaları oluşturma başlıklı makaleyi inceleyin. Bu API'leri uygulayan bir sesli kontrol uygulaması, diğerlerinin yanı sıra şunları yapabilir:

  • Medya kaynağı seçimine sorunsuz bir şekilde katılma
  • Araç yeniden başlatıldıktan sonra otomatik olarak devam eder.
  • Medya Merkezi kullanıcı arayüzünü kullanarak oynatma ve göz atma kontrolü sağlama
  • Standart donanım medya düğmesi etkinliklerini alma

Tüm navigasyon uygulamalarıyla etkileşime geçmenin standart bir yolu yoktur. Google Haritalar ile entegrasyonlar için Android Automotive Intents için Google Haritalar başlıklı makaleyi inceleyin. Diğer uygulamalarla entegrasyon için doğrudan uygulama geliştiricileriyle iletişime geçin. Herhangi bir uygulamada (Google Haritalar dahil) intent başlatmadan önce intent'in çözülebileceğini doğrulayın (Intent isteklerine bakın). Bu sayede, hedef uygulama kullanılamıyorsa kullanıcıyı bilgilendirme fırsatı elde edilir.

Araç komutlarını yerine getirme

Araç özelliklerine hem okuma hem de yazma için erişim CarPropertyManager aracılığıyla sağlanır. Araç mülkleri türleri, bunların uygulanması ve diğer ayrıntılar Mülk yapılandırmaları bölümünde açıklanmıştır. Android tarafından desteklenen özelliklerin doğru açıklaması için doğrudan hardware/interfaces/automotive/vehicle/2.0/types.hal sayfasına bakmanız önerilir. Burada tanımlanan VehicleProperty enum'u hem standart hem de tedarikçiye özgü mülkleri, veri türlerini, değişiklik modunu, birimleri ve okuma/yazma erişim tanımını içerir.

Java'dan aynı sabitlere erişmek için VehiclePropertyIds ve tamamlayıcı sınıflarını kullanabilirsiniz. Farklı mülklerin erişimini kontrol eden farklı Android izinleri vardır. Bu izinler CarService manifest dosyasında tanımlanır. Mülkler ile izinler arasındaki eşleme, VehiclePropertyIds Javadoc'ında açıklanır ve PropertyHalServiceIds'de uygulanır.

Araç özelliğini okuma

Aşağıda, araç hızının nasıl okunacağını gösteren bir örnek verilmiştir:

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);
    }

    ...
}

Araç özelliği ayarlama

Aşağıda, ön klimanın nasıl açılıp kapatılacağı gösterilmektedir.

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"));
    }

    …
}

İletişim komutlarını yerine getirme

Mesajlaşma komutlarını işleme

VIA'lar, gelen mesajları Sesli Asistan'da dokunarak okuma bölümünde açıklanan "dokunarak okuma" akışını izleyerek işlemelidir. Bu akış, isteğe bağlı olarak gelen mesajın gönderenine yanıt göndermeyi de işleyebilir. Ayrıca, VIA'lar doğrudan arabadan veya Bluetooth üzerinden SMS mesajları oluşturmak ve göndermek için SmsManager (android.telephony paketinin bir parçası) kullanabilir.

Arama komutlarını işleme

Benzer şekilde, VIA'lar telefon araması yapmak ve kullanıcının sesli mesaj numarasını aramak için TelephonyManager simgesini kullanabilir. Bu gibi durumlarda, VIA'lar doğrudan telefon yığını veya Car Dialer uygulamasıyla etkileşim kurar. Her durumda, kullanıcıya sesli aramayla ilgili kullanıcı arayüzünü gösteren Car Dialer uygulaması olmalıdır.

Diğer komutları yerine getirme

VIA ile sistem arasında olası diğer entegrasyon noktalarının listesi için bilinen Android intent'lerinin listesini inceleyin. Birçok kullanıcı komutu sunucu tarafında çözülebilir (ör. kullanıcıların e-postalarını ve takvim etkinliklerini okuma) ve sesli etkileşim dışında sistemle herhangi bir etkileşim gerektirmez.

Immersive actions (display visual content)

Kullanıcı işlemlerini veya anlayışını geliştirdiği durumlarda VIA, araç ekranında ek görsel içerik sağlayabilir. Sürücünün dikkatini dağıtmamak için bu tür içerikleri basit, kısa ve uygulanabilir tutun. Tam sayfa işlemlerle ilgili kullanıcı arayüzü/kullanıcı deneyimi yönergeleri hakkında ayrıntılı bilgi için Önceden yüklenmiş asistanlar: Kullanıcı deneyimi rehberliği başlıklı makaleyi inceleyin.

VIA'lar, ana birimin (HU) tasarımının geri kalanıyla tutarlılığı ve özelleştirmeyi sağlamak için kullanıcı arayüzü öğelerinin çoğunda Car UI Library bileşenlerini kullanmalıdır. Ayrıntılar için Özelleştirme bölümüne bakın.