Arsitektur preferensi pengguna dan panduan penerapan

Halaman ini memberikan panduan tentang arsitektur sistem Preferensi Pengguna SDV dan petunjuk untuk menerapkan layanan dan klien yang dapat dikontrol pengguna.

Ringkasan arsitektur

Sistem Preferensi Pengguna memisahkan penyimpanan dan pengelolaan setelan pengguna dari penerapan dan aplikasi setelan tersebut. Istilah arsitektur utama diringkas dalam tabel:

FiturDeskripsiPeranTanggung jawab
Layanan yang dapat dikontrol pengguna Paket layanan SDV standar yang mengelola domain tertentu (misalnya, HVAC, kursi mobil, audio) Menyediakan status yang dimaksudkan dari kemampuan dan batasan hardware atau subsistem yang dikontrolnya.
  • Pendaftaran: Memberi tahu agen preferensi pengguna tentang setelan yang didukungnya (metadata, default, batasan).
  • Penerapan dan otonomi: Menerima permintaan untuk mengubah setelan, memvalidasinya berdasarkan aturan keamanan dan status saat ini, serta menerapkannya ke hardware. Mempertahankan otonomi penuh dan menentukan apakah perubahan setelan diterima atau ditolak.
Agen preferensi pengguna Orchestrator pusat Menyediakan penyimpanan terpusat, pengelolaan profil pengguna, dan hub notifikasi.
  • Penyimpanan: Mempertahankan setelan per pengguna (misalnya, pengemudi, penumpang).
  • Perutean: Proxy mengubah permintaan dari klien (misalnya, antarmuka mesin manusia (HMI)) ke layanan yang dapat dikontrol pengguna yang sesuai.
  • Notifikasi: Menyiarkan perubahan kepada pihak yang berkepentingan (tampilan atau HMI) menggunakan antarmuka ChangeNotifier.
  • Pengelolaan pengguna: Menangani peralihan pengguna dan menerapkan status persisten yang benar ke semua layanan terdaftar.
Klien preferensi pengguna Aplikasi atau layanan yang menyediakan antarmuka pengguna, misalnya, aplikasi IVI dengan HMI atau logika lain yang perlu berinteraksi dengan preferensi pengguna Berinteraksi dengan pengguna, menampilkan setelan, dan memulai permintaan perubahan.
  • Tampilan: Menampilkan setelan dan batasan saat ini kepada pengguna.
  • Minta perubahan: Mengirim modifikasi setelan yang dimulai pengguna ke agen preferensi pengguna.
  • Menerima notifikasi: Berlangganan dan bereaksi terhadap update setelan real-time.

Mengimplementasikan layanan yang dapat dikontrol pengguna

Untuk memberi tahu agen Preferensi Pengguna tentang kunci yang ada, jenis datanya, nilai default, dan batasan (misalnya, nilai minimum dan maksimum), paket layanan Anda harus berinteraksi dengan antarmuka UserPreferencesRegistryService. Saat layanan Anda dimulai, layanan tersebut harus mendaftarkan setelan yang dieksposnya. Agen memanggil RequestSettingsChange di layanan Anda saat pengguna mencoba mengubah setelan (atau saat beralih pengguna).

Ikuti langkah-langkah di bagian ini untuk mengizinkan Preferensi Pengguna (dan pengguna dengan HMI) mengontrol layanan Anda.

  1. Tentukan antarmuka layanan dalam file VSIDL:

    • Sebagai server, terapkan com.sdv.google.user_preferences.user_controllable.UserControllableService. Cara ini memungkinkan agen mengirimkan permintaan perubahan kepada Anda.
    • Sebagai klien, gunakan com.sdv.google.user_preferences.UserPreferencesRegistryService. Tindakan ini mendaftarkan setelan Anda saat startup.

    Contoh berikut menunjukkan service_bundle.vsidl untuk layanan yang dapat dikontrol pengguna:

    service_bundle {
        name: "MyFeatureService"
        server {
            service: "com.sdv.google.user_preferences.user_controllable.UserControllableService"
        }
        client {
            service: "com.sdv.google.user_preferences.UserPreferencesRegistryService"
        }
    }
    
  2. Mendaftarkan setelan saat startup di proto kunci user_preferences_registry_service.proto:

    1. Hubungkan ke UserPreferencesRegistryService.
    2. Buat instance RegisterSettingsRequest.
    3. Tentukan instance SettingsGroup (kumpulan logis setelan).
    4. Untuk setiap setelan, tentukan:

      *   **Key:** Unique string ID (for example, `TEMPERATURE`)
      *   **Kind:** `PER_USER` (stored per user profile) or `SHARED`
          (global)
      *   **Default value:** Initial value if no user preference exists
      *   **Constraints:** (optional) Validation rules (for example, Min
          16, Max 32 for HVAC).
      
    5. Panggil RegisterSettings().

    Contoh berikut ada di Rust konseptual:

    let temperature_setting = SettingDefinition {
        name: "TEMPERATURE".to_string(),
        kind: SettingKind::PER_USER.into(),
        default_value: Value::Int64(22), // Default 22 degrees
        constraint: Some(Constraints::Int64Constraints(Int64Constraints {
            min_value: Some(16),
            max_value: Some(32),
            ..Default::default()
        })),
        ..Default::default()
    };
    
    registry_client.RegisterSettings(&RegisterSettingsRequest {
        group_name: "HVAC".to_string(),
        version: "1.0".to_string(),
        settings_definitions: vec![temperature_setting],
    }).await?;
    
  3. Menangani permintaan perubahan setelan di user_controllable_service.proto:

    1. Terapkan RPC RequestSettingsChange.
    2. Validasi apakah nilai yang diminta valid dalam konteks saat ini (misalnya, apakah hardware sudah siap).
    3. Terapkan logika tertentu untuk menerapkan perubahan (misalnya, pindahkan kursi, ubah kecepatan kipas).
    4. Menampilkan nilai yang diterapkan di RequestSettingsChangeResponse:
    5. Jika Anda menerima perubahan, kembalikan nilai baru.
    6. Jika Anda menolak atau membatasi nilai, tampilkan nilai yang Anda tetapkan (atau pertahankan).

    Contoh berikut ada di Rust konseptual:

    async fn RequestSettingsChange(
        &self,
        _caller_id: ServiceFqin,
        request: &RequestSettingsChangeRequest
    ) -> SdvResult<RequestSettingsChangeResponse> {
        let mut applied_settings = Vec::new();
    
        for setting in &request.settings {
            if self.hardware.set_value(setting.key, setting.value).is_ok() {
                // Change accepted
                applied_settings.push(setting.clone());
            } else {
                // Change rejected, return current actual value
                let current_val = self.hardware.get_value(setting.key);
                applied_settings.push(create_setting(setting.key, current_val));
            }
        }
    
        Ok(RequestSettingsChangeResponse {
            settings: applied_settings,
        })
    }
    
  4. Terapkan RPC FactoryReset untuk mengembalikan subsistem Anda ke status bersih:

    1. Mereset semua setelan ke nilai defaultnya (seperti yang ditentukan dalam konfigurasi kode).
    2. Panggil UpdateSettings di layanan pendaftaran untuk memberi tahu agen bahwa nilai telah berubah secara eksternal (dengan reset, bukan dengan permintaan pengguna).

Kompatibilitas mundur dan evolusi skema

Skema setelan yang ditentukan oleh layanan yang dapat dikontrol pengguna dianggap sebagai antarmuka publik. Antarmuka ini digunakan oleh agen preferensi pengguna dan berbagai klien (misalnya, HMI), yang mungkin memiliki jadwal rilis yang berbeda. Oleh karena itu, mempertahankan kompatibilitas mundur yang ketat sangat penting untuk mencegah ketidakstabilan sistem dan kerusakan klien.

Perubahan yang kompatibel

Layanan yang dapat dikontrol pengguna hanya boleh memperkenalkan perubahan yang kompatibel pada skema setelannya. Perubahan ini memastikan klien lama terus beroperasi dengan benar tanpa update:

  • Tambahkan setelan opsional baru dengan nilai default yang wajar:

    • Setelan ini bersifat opsional, sehingga klien harus memeriksa keberadaannya untuk mendukung berbagai versi layanan.
    • Klien mengabaikan setelan ini jika belum diupdate untuk mengenalinya.
    • Jika tidak ada preferensi pengguna untuk setelan baru, agen akan menggunakan nilai default yang diberikan.

Perubahan yang tidak kompatibel

Perubahan berikut dianggap merusak dan dilarang karena langsung membahayakan klien lama:

  • Hapus setelan yang ada.

  • Mengubah arti, unit, atau jenis data setelan yang ada (misalnya, mengubah dari bilangan bulat yang merepresentasikan suhu dalam Celsius menjadi float yang merepresentasikan tekanan dalam Pascal).

  • Mengubah nilai default setelan yang ada. Alasan utama melarang perubahan nilai default adalah potensi komplikasi dengan migrasi data yang dipertahankan. Agen menyimpan setelan berdasarkan skema pendaftaran layanan. Mengubah nilai default akan memerlukan logika yang kompleks untuk memigrasikan semua profil pengguna yang ada ke default baru atau berisiko menggunakan nilai yang secara teknis salah untuk pengguna yang tidak pernah secara eksplisit menetapkan preferensi.

Menangani perubahan yang dapat menyebabkan gangguan yang diperlukan

Jika perubahan yang menyebabkan gangguan diperlukan, layanan tidak boleh mengubah setelan yang ada. Pendekatan untuk mengelola transisi ini sekaligus mempertahankan kompatibilitas terutama terletak di logika layanan yang dapat dikontrol pengguna:

  1. Buat setelan baru dengan definisi, kunci, atau unit baru yang diinginkan.
  2. Menghentikan penggunaan setelan yang ada dengan mendaftarkannya untuk kompatibilitas. Gunakan setelan baru ini saat Anda mengembangkan klien baru.
  3. Menyarankan klien baru untuk menerapkan logika kompatibilitas dalam logika bisnis layanan yang dapat dikontrol pengguna.

Implementasi RequestSettingsChange layanan harus memastikan bahwa perubahan pada satu setelan akan diterapkan pada setelan yang tidak digunakan lagi, dan perubahan pada setelan yang tidak digunakan lagi akan diterapkan pada setelan.

Contoh logika kompatibilitas:

  1. Layanan menghentikan penggunaan setelan lama TEMPERATURE_C (Celsius) dan memperkenalkan TEMPERATURE_K (Kelvin).

  2. Saat agen mengirim permintaan untuk memperbarui setelan baru:

    • Layanan menerima permintaan untuk TEMPERATURE_K (misalnya, 295,15 K).

    • Logika layanan mengonversi nilai ini ke Celsius (22°C) dan secara internal memperbarui serta mempertahankan kedua nilai untuk menjaga konsistensi bagi klien lama.

  3. Saat agen mengirim permintaan untuk setelan yang tidak digunakan lagi dari klien lama:

    • Layanan menerima permintaan untuk TEMPERATURE_C (misalnya, 24°C).
    • Layanan mengonversi nilai ini menjadi Kelvin (297,15 K) dan secara internal memperbarui serta mempertahankan kedua nilai.

Strategi penulisan ganda ini memastikan bahwa semua klien, terlepas dari jadwal rilisnya, membaca data yang konsisten dan akurat, sehingga menghindari kerusakan yang disebabkan oleh ketidakcocokan rilis eksternal.

Mengimplementasikan klien

Untuk menerapkan klien (misalnya, HMI) yang berinteraksi dengan agen User Preferences:

  1. Tentukan paket layanan klien Anda untuk berinteraksi dengan antarmuka Preferensi Pengguna tertentu. Dalam file VSIDL Anda:

    • Sebagai server, terapkan com.sdv.google.user_preferences.view.ChangeNotifier untuk memungkinkan agen mengirim notifikasi real-time kepada klien Anda tentang perubahan setelan.
    • Sebagai klien, gunakan com.sdv.google.user_preferences.UserPreferencesManagementService untuk meminta modifikasi setelan dan berlangganan update.
    • Sebagai klien, gunakan com.sdv.google.user_preferences.UserPreferencesAdminService untuk mengelola profil pengguna (misalnya, membuat, memilih, menghapus, mereset ke setelan pabrik).

    Contoh berikut menunjukkan file service_bundle.vsidl untuk klien:

    service_bundle {
        name: "MyHmiClient"
        server {
            service: "com.sdv.google.user_preferences.view.ChangeNotifier"
        }
        client {
            service: "com.sdv.google.user_preferences.UserPreferencesManagementService"
        }
        client {
            service: "com.sdv.google.user_preferences.UserPreferencesAdminService"
        }
    }
    

    Tambahkan kebijakan otorisasi yang sesuai. Untuk mengizinkan komunikasi bagi agen preferensi pengguna, buat klien untuk server yang ditentukan. Contoh:

    server {
        service: "com.sdv.google.user_preferences.view.ChangeNotifier"
        allow_all_channels: true
    }
    client {
        service: "com.sdv.google.user_preferences.UserPreferencesManagementService"
        allow_all_channels: true
    }
    client {
        service: "com.sdv.google.user_preferences.UserPreferencesAdminService"
        allow_all_channels: true
    }
    
  2. Anda dapat mengubah setelan permintaan di UserPreferencesManagementService:

    1. Hubungkan ke UserPreferencesManagementService.
    2. Buat instance RequestSettingsChangeRequest, dengan menentukan SettingsGroupId dan setelan yang diinginkan.
    3. Opsional. Tetapkan ChangePersistencePolicy ke PERSISTENT_CHANGE (default) atau NON_PERSISTENT_CHANGE.
    4. Panggil RequestSettingsChange().

    Contoh berikut ada di Rust konseptual:

    management_client.RequestSettingsChange(&RequestSettingsChangeRequest {
        settings_group_id: Some(SettingsGroupId {
            service_fqin: hvac_service_fqin.to_string(),
            name: "HVAC".to_string(),
            ..Default::default()
        }).into(),
        settings: vec![Setting {
            key: "TEMPERATURE".to_string(),
            value: Some(Value::Int64(24)),
            ..Default::default()
        }],
        change_persistence_policy: ChangePersistencePolicy::PERSISTENT_CHANGE.into(),
        ..Default::default()
    }).await?;
    
  3. Berlangganan perubahan setelan dengan user_preferences_management_service.proto dan change_notifier.proto:

    1. Terapkan RPC OnSettingsChange dari antarmuka ChangeNotifier dalam paket layanan Anda. Agen Preferensi Pengguna memanggil metode ini saat terjadi perubahan.
    2. Hubungkan ke UserPreferencesManagementService.
    3. Buat SubscribeToSettingsChangeAndGetSettingsRequest yang menentukan SettingsGroupId yang ingin Anda pantau.
    4. Untuk menampilkan status setelan, lalu mengirimkan pembaruan mendatang melalui implementasi OnSettingsChange Anda, panggil SubscribeToSettingsChangeAndGetSettings().

    Contoh berikut tentang penerapan antarmuka ChangeNotifier ada di Rust konseptual:

    #[async_trait]
    impl ChangeNotifier for MyHmiServiceImpl {
        async fn OnSettingsChange(
            &self,
            _caller_id: ServiceFqin,
            request: &OnSettingsChangeRequest,
        ) -> SdvResult<OnSettingsChangeResponse> {
            // Process the active_settings, pending_changes, and persisted_settings
            // Update your UI or internal state accordingly.
            info!("Received settings change for group: {}", request.settings_group_id.name);
            // ...
            Ok(OnSettingsChangeResponse::new())
        }
    }
    

    Contoh berikut tentang berlangganan ada di Rust konseptual:

    management_client.SubscribeToSettingsChangeAndGetSettings(&SubscribeToSettingsChangeAndGetSettingsRequest {
        settings_group_id: Some(SettingsGroupId {
            service_fqin: hvac_service_fqin.to_string(),
            name: "HVAC".to_string(),
            ..Default::default()
        }).into(),
        ..Default::default()
    }).await?;
    
  4. Opsional: Klien yang mengelola profil pengguna (misalnya, aplikasi setelan khusus) dapat menggunakan user_preferences_admin_service.proto untuk berinteraksi dengan layanan admin:

    1. Hubungkan ke UserPreferencesAdminService.
    2. Gunakan RPC seperti CreateUser, SelectUser, DeleteUser, FactoryReset, dan ListUsers untuk mengelola profil pengguna.

    Contoh berikut tentang cara membuat pengguna ada di Rust konseptual:

    admin_service_client.CreateUser(&CreateUserRequest {
        user: Some(User {
            id: 1,
            flags: UserFlags::DRIVER.value(),
            ..Default::default()
        }).into(),
        ..Default::default()
    }).await?;
    
  5. Temukan setelan dan pengguna yang tersedia melalui layanan admin dengan user_preferences_admin_service.proto:

    1. Dapatkan daftar semua pengguna terdaftar dengan memanggil ListUsers() di UserPreferencesAdminService.
    2. Dapatkan setelan untuk pengguna tertentu dengan memanggil GetUserSettings(user_id) di UserPreferencesAdminService.

    Contoh berikut tentang mencantumkan pengguna dan mendapatkan setelan ada di Rust konseptual:

    // List all users
    let list_users_response = admin_service_client.ListUsers(&ListUsersRequest::new()).await?;
    info!("Available users: {:?}", list_users_response.users);
    
    // Get settings for a specific user (for example, user with ID 1)
    if let Some(user_id) = list_users_response.users.first().map(|u| u.id) {
        let get_settings_response = admin_service_client.GetUserSettings(&GetUserSettingsRequest {
            user_id,
            ..Default::default()
        }).await?;
        info!("Settings for user {}: {:?}", user_id, get_settings_response.groups);
    }
    

Ringkasan alur

  1. Klien memulai dan terhubung ke layanan pengelolaan dan administrasi agen.
  2. Klien menemukan dan berlangganan grup setelan serta menampilkan status awal.
  3. Klien mengirimkan RequestSettingsChange ke agen.
  4. Agen mengirimkan notifikasi OnSettingsChange ke klien dengan setelan dan status yang diperbarui.

Untuk contoh kerja lengkap, lihat HMIService di @samples/user_preferences/v1/.

Menerapkan agen

Paket layanan yang diluncurkan oleh orkestrator menerapkan agen preferensi pengguna. Untuk mempermudah, implementasi referensi disediakan.

Selain itu, file user_preferences_sample.vsidl paket layanan contoh ini untuk agen disediakan:

package: "com.sdv.oem.user_preferences"

service_bundle {
    name: "UserPreferencesServiceBundle"
    server {
        service: "com.sdv.google.user_preferences.UserPreferencesAdminService"
    }
    server {
        service: "com.sdv.google.user_preferences.UserPreferencesManagementService"
    }
    server {
        service: "com.sdv.google.user_preferences.UserPreferencesRegistryService"
    }
    client {
        service: "com.sdv.google.user_preferences.view.ChangeNotifier"
    }
    client {
        service: "com.sdv.google.user_preferences.user_controllable.UserControllableService"
    }
}

Implementasi dapat menggunakan middleware yang dihasilkan dan harus dikompilasi menjadi rust_ffi_shared yang dirujuk oleh paket layanan yang menerapkan agen preferensi pengguna:

sdv_service_bundle_metadata {
  # This name must match the agent's Bundle Name
  name: "UserPreferencesServiceBundle"
  version_number: 1
  version_name: "1"

  native_library_path: "lib64/<USER-PREFERENCES-FFI-LIB>.so"

  orchestration_config_path: "etc/user_preferences_service_bundle/<USER-PREFERENCES-ORCHESTRATION>.textproto"

  authorization_policy_path: "etc/user_preferences_service_bundle/permissions.textproto"
}

File kebijakan otorisasi .textproto klien memerlukan izin yang diperlukan:

client {
    service: "com.sdv.google.user_preferences.UserPreferencesManagementService"
    allow_all_channels: true
}

client {
    service: "com.sdv.google.user_preferences.UserPreferencesRegistryService"
    allow_all_channels: true
}

client {
    service: "com.sdv.google.user_preferences.UserPreferencesAdminService"
    allow_all_channels: true
}

Lampiran: konsep utama

Bagian ini menjelaskan beberapa konsep utama.

Pengguna

Setiap pengguna kendaraan (kelas User) dapat membuat akun tempat mereka dapat menyimpan preferensi mereka. Preferensi Pengguna hanya mendukung akun untuk pengemudi kendaraan. Pengemudi tamu dapat membuat akun sementara yang otomatis dihapus setelah digunakan satu kali.

message User {
  // Required.
  // A unique ID for the user.
  int32 id = 1;

  // Bit flags that define properties of user. Integer values have to be powers of 2 as they are used as
  // a bit mask.
  enum UserFlags {
    // Due to Protobuff requirement to have the first enum option set to 0,
    // Assign 0 to an unused flag
    UNSET = 0x0;
    // Marks the user as vehicle driver
    DRIVER = 0x01;
    // Ephemeral users have non-persistent state, once another user is selected
    // the profile is deleted automatically
    EPHEMERAL = 0x02;
  }

  // Required.
  // Bitmask for the user flags defined above
  int32 flags = 2;
}

Grup setelan

Grup setelan (kelas SettingsGroup) mengatur dan mengelola setelan terkait. Setiap komponen yang dapat dikonfigurasi dalam kendaraan menentukan setelannya sebagai grup, yang terdiri dari daftar setelan yang ditampilkan sebagai key-value pair. Misalnya, kendaraan dengan kursi elektrik dapat menentukan grup setelan untuk kursi pengemudi dan grup lain untuk penumpang depan yang keduanya berisi setelan dengan nama yang sama.

message SettingsGroup {
  // Required.
  // The identifier for this group.
  SettingsGroupId id = 1;

  // Required.
  // The version number of schema used by this setting group.
  string version = 2;

  // Required.
  // The list of settings within the setting group.
  repeated Setting settings = 3;
}

Setelan

Setelan, pesan (class Setting), mewakili satu setelan dalam SettingsGroup. Pesan ini terdiri dari kunci, yang merupakan nama setelan dan nilai, yang dapat berupa salah satu dari beberapa jenis.

Contoh ini menunjukkan cara setelan direpresentasikan dengan kunci dan nilai:

// A key value pair representing a setting within a UserControllableService SettingsGroup.
message Setting {
  // Required.
  // A name that uniquely identifies a setting within a SettingsGroup.
  string key = 1;

  // Required.
  // New value of the setting.
  oneof value {
    bool bool = 2;
    float float = 3;
    int32 int32 = 4;
    int64 int64 = 5;
    bytes blob = 6;
    int32 enum = 7;
  }
}

Menyetel definisi

Definisi setelan (kelas SettingDefinition) berfungsi sebagai template untuk setelan individual dalam grup setelan. Setelan ini menentukan karakteristik mendasar setelan, seperti apakah setelan dibagikan ke semua pengguna, khusus untuk setiap pengguna, atau dikelola secara eksternal (passthrough).

Yang penting, definisi setelan juga menentukan batasan apa pun pada nilai setelan, seperti nilai minimum dan maksimum, kenaikan yang diizinkan, atau serangkaian opsi yang dibatasi. Batasan ini menghasilkan integritas dan konsistensi data untuk setiap setelan.

// The definition of a setting, along with its properties such as type and constraints
message SettingDefinition {
  // Required.
  SettingKind kind = 1;

  // Required.
  SettingWithConstraints setting_with_constraints = 2;
}

enum SettingKind {
  // A setting which is applied for all vehicle users.
  SHARED = 0;
  // Store the value of the setting for each vehicle user separately.
  PER_USER = 1;
  // UserControllableService is fully responsible for the storage of PASSTHROUGH setting.
  // User Preferences only notifies UserControllableService when the value is explicitly set by
  // user. User Preferences does not attempt to request changes based on user change or service
  // registration.
  PASSTHROUGH = 2;
};

message SettingWithConstraints {
  // Required
  Setting setting = 1;

  // Required.
  // Defines restrictions on the setting's value
  oneof constraints {
    FloatConstraints float_constraints = 2;
    Int32Constraints int32_constraints = 3;
    Int64Constraints int64_constraints = 4;
    EnumConstraints enum_constraints = 5;
  }
}

message Int32Constraints {
  // The minimum value that a setting can have.
  optional int32 min_value = 1;
  // The maximum value that a setting can have.
  optional int32 max_value = 2;
  // The step by which a setting's value can be increased or decreased.
  optional int32 step = 3;
}

message Int64Constraints {
  // The minimum value that a setting can have.
  optional int64 min_value = 1;
  // The maximum value that a setting can have.
  optional int64 max_value = 2;
  // The step by which a setting's value can be increased or decreased.
  optional int64 step = 3;
}

message FloatConstraints {
  // The minimum value that a setting can have.
  optional float min_value = 1;
  // The maximum value that a setting can have.
  optional float max_value = 2;
  // The step by which a setting's value can be increased or decreased.
  optional float step = 3;
}

message EnumConstraints {
  // Required.
  // List of unique values sorted in ascending order.
  repeated int32 possible_values = 1;
}

Contoh urutan peristiwa saat pengguna memperbarui setelan

Contoh ini menggambarkan urutan peristiwa yang terjadi saat pengguna menggunakan infotainment dalam kendaraan (IVI) Android Automotive OS (AAOS) untuk memperbarui setelan:

Acara saat pengguna mengubah setelan

Gambar 1. Peristiwa saat pengguna mengubah setelan.

Contoh urutan peristiwa saat kendaraan dinyalakan

Contoh ini menggambarkan cara Preferensi Pengguna SDV menerapkan setelan pilihan pengguna saat kendaraan dinyalakan:

Peristiwa saat kendaraan
mulai

Gambar 2. Peristiwa saat kendaraan dinyalakan.