دليل تصميم وتنفيذ إعدادات المستخدم المفضَّلة

تقدّم هذه الصفحة دليلًا حول بنية نظام "الإعدادات المفضّلة للمستخدم" في SDV وتعليمات لتنفيذ خدمة وعميل يمكن للمستخدم التحكّم فيهما.

نظرة عامة على البنية

يفصل نظام "الإعدادات المفضّلة للمستخدم" بين تخزين إعدادات المستخدم وإدارتها من جهة، وتطبيق هذه الإعدادات وفرضها من جهة أخرى. يرد في الجدول ملخّص للمصطلحات المعمارية الرئيسية:

الميزةالوصفالدورالمسؤولية
الخدمة التي يمكن للمستخدم التحكّم فيها حزمة خدمات SDV عادية تدير نطاقًا معيّنًا (مثل التدفئة والتهوية وتكييف الهواء أو مقاعد السيارة أو الصوت) توفّر الحالة المقصودة لقدرات الأجهزة أو النظام الفرعي الذي تتحكّم فيه وقيوده.
  • التسجيل: تُعلم وكيل الإعدادات المفضّلة للمستخدم بالإعدادات التي يتيحها (البيانات الوصفية والإعدادات التلقائية والقيود).
  • التطبيق والاستقلالية: تتلقّى طلبات تغيير الإعدادات، وتتحقّق من صحتها مقارنةً بالحالة الحالية وقواعد الأمان، وتطبّقها على الأجهزة. تحتفظ الخدمة باستقلاليتها الكاملة وتحدّد ما إذا كان سيتم قبول تغيير الإعداد أو رفضه.
وكيل الإعدادات المفضّلة للمستخدم المنسّق المركزي يوفّر مساحة تخزين مركزية وإدارة الملفات الشخصية للمستخدمين ومركز إشعارات.
  • مساحة التخزين: يحتفظ بالإعدادات لكل مستخدم (مثل السائق والراكب).
  • التوجيه: يرسل طلبات التغيير من العملاء (مثل واجهة التفاعل بين الإنسان والآلة) إلى الخدمة المناسبة التي يمكن للمستخدم التحكّم فيها.
  • الإشعارات: يبثّ التغييرات إلى الأطراف المعنيّة (طرق العرض أو واجهات التفاعل بين الإنسان والآلة) باستخدام واجهة ChangeNotifier.
  • إدارة المستخدمين: يتعامل مع تبديل المستخدمين وتطبيق الحالة الثابتة الصحيحة على جميع الخدمات المسجّلة.
عميل الإعدادات المفضّلة للمستخدم تطبيق أو خدمة توفّر واجهة مستخدم، مثل تطبيق نظام المعلومات والترفيه داخل السيارة مع واجهة تفاعل بين الإنسان والآلة أو منطق آخر يحتاج إلى التفاعل مع الإعدادات المفضّلة للمستخدم يتفاعل مع المستخدمين ويعرض الإعدادات ويبدأ طلبات التغيير.
  • العرض: يعرض الإعدادات والقيود الحالية للمستخدم.
  • طلب التغييرات: يرسل التعديلات التي يبدأها المستخدم على الإعدادات إلى وكيل الإعدادات المفضّلة للمستخدم.
  • تلقّي الإشعارات: يشترك في التحديثات في الوقت الفعلي للإعدادات ويتفاعل معها.

تنفيذ خدمة يمكن للمستخدم التحكّم فيها

لإعلام وكيل "الإعدادات المفضّلة للمستخدم" بالمفاتيح المتوفّرة وأنواع بياناتها وقيمها التلقائية وقيودها (مثل الحد الأدنى والحد الأقصى للقيم)، يجب أن تتفاعل حزمة الخدمات مع واجهة UserPreferencesRegistryService. عند بدء الخدمة، يجب تسجيل الإعدادات التي تعرضها. يطلب الوكيل من خدمتك تنفيذ RequestSettingsChange عندما يحاول المستخدم تعديل إعداد (أو عند تبديل المستخدمين).

اتّبِع الخطوات الواردة في هذا القسم للسماح لخدمة "الإعدادات المفضّلة للمستخدم" (ومستخدم لديه واجهة تفاعل بين الإنسان والآلة) بالتحكّم في خدمتك.

  1. حدِّد واجهات الخدمة في ملف VSIDL:

    • بصفتك خادمًا، نفِّذ com.sdv.google.user_preferences.user_controllable.UserControllableService. يسمح ذلك للوكيل بإرسال طلبات التغيير إليك.
    • بصفتك عميلاً، استخدِم com.sdv.google.user_preferences.UserPreferencesRegistryService. يؤدي ذلك إلى تسجيل إعداداتك عند بدء التشغيل.

    يوضّح المثال التالي service_bundle.vsidl لخدمة يمكن للمستخدم التحكّم فيها:

    service_bundle {
        name: "MyFeatureService"
        server {
            service: "com.sdv.google.user_preferences.user_controllable.UserControllableService"
        }
        client {
            service: "com.sdv.google.user_preferences.UserPreferencesRegistryService"
        }
    }
    
  2. سجِّل الإعدادات عند بدء التشغيل في نموذج البيانات الأساسي user_preferences_registry_service.proto:

    1. اتّصِل بـ UserPreferencesRegistryService.
    2. أنشِئ مثيلاً من RegisterSettingsRequest.
    3. حدِّد مثيلاً من SettingsGroup (مجموعة منطقية من الإعدادات).
    4. لكل إعداد، حدِّد ما يلي:

      *   **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. نفِّذ RegisterSettings().

    المثال التالي مكتوب بلغة Rust المفاهيمية:

    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. تعامَل مع طلبات تغيير الإعدادات في user_controllable_service.proto:

    1. نفِّذ طلب الإجراء عن بُعد RequestSettingsChange.
    2. تحقَّق مما إذا كانت القيم المطلوبة صالحة في السياق الحالي (على سبيل المثال، إذا كانت الأجهزة جاهزة).
    3. طبِّق منطقًا معيّنًا لتطبيق التغيير (على سبيل المثال، حرِّك المقعد أو غيِّر سرعة المروحة).
    4. أرسِل القيم التي تم تطبيقها في RequestSettingsChangeResponse:
    5. إذا قبلت التغيير، أرسِل القيمة الجديدة.
    6. إذا رفضت القيمة أو قيّدتها، أرسِل القيمة التي ضبطتها (أو احتفظت بها).

    المثال التالي مكتوب بلغة Rust المفاهيمية:

    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. نفِّذ طلب الإجراء عن بُعد FactoryReset لإعادة النظام الفرعي إلى حالة نظيفة:

    1. أعِد ضبط جميع الإعدادات إلى قيمها التلقائية (كما هو محدّد في إعدادات الرمز البرمجي).
    2. نفِّذ UpdateSettings على خدمة التسجيل لإعلام الوكيل بأنّ القيم قد تغيّرت خارجيًا (من خلال إعادة الضبط، وليس من خلال طلب مستخدم).

التوافق مع الإصدارات السابقة وتطوير المخطط

يُعدّ مخطط الإعدادات الذي تحدّده خدمة يمكن للمستخدم التحكّم فيها واجهة علنية. يستخدم هذه الواجهة وكيل الإعدادات المفضّلة للمستخدم والعديد من العملاء (مثل واجهات التفاعل بين الإنسان والآلة)، الذين قد يكون لديهم جداول إصدار مختلفة. لذلك، من الضروري الحفاظ على توافق صارم مع الإصدارات السابقة لمنع عدم استقرار النظام وتعطّل العملاء.

التغييرات المتوافقة

يجب ألا تُدخل خدمة يمكن للمستخدم التحكّم فيها إلا تغييرات متوافقة على مخطط إعداداتها. تضمن هذه التغييرات استمرار عمل العملاء القدامى بشكلٍ صحيح بدون تحديثات:

  • أضِف إعدادًا جديدًا اختياريًا بقيمة تلقائية معقولة:

    • هذا الإعداد اختياري، لذا يجب أن يتحقّق العملاء من وجوده لدعم إصدارات مختلفة من الخدمة.
    • يتجاهل العملاء هذا الإعداد إذا لم يتم تعديلهم للتعرّف عليه.
    • إذا لم تكن هناك إعدادات مفضّلة للمستخدم للإعداد الجديد، يستخدم الوكيل القيمة التلقائية المقدَّمة.

التغييرات غير المتوافقة

تُعدّ التغييرات التالية غير متوافقة ومحظورة لأنّها تؤثر على الفور في العملاء القدامى:

  • إزالة إعداد حالي

  • تغيير معنى إعداد حالي أو وحدته أو نوع بياناته (على سبيل المثال، التغيير من عدد صحيح يمثّل درجة الحرارة بالدرجة المئوية إلى عدد عائم يمثّل الضغط بالباسكال)

  • تغيير القيمة التلقائية لإعداد حالي السبب الرئيسي لحظر تغييرات القيمة التلقائية هو احتمال حدوث تعقيدات في نقل البيانات الثابتة. يخزّن الوكيل الإعدادات استنادًا إلى مخطط التسجيل الخاص بالخدمة. سيؤدي تغيير القيمة التلقائية إلى الحاجة إلى منطق معقّد لنقل جميع الملفات الشخصية الحالية للمستخدمين إلى القيمة التلقائية الجديدة أو المخاطرة باستخدام قيمة غير صحيحة من الناحية الفنية للمستخدمين الذين لم يضبطوا الإعدادات المفضّلة بشكلٍ صريح.

التعامل مع التغييرات غير المتوافقة المطلوبة

إذا كان هناك تغيير غير متوافق مطلوب، يجب ألا تعدِّل الخدمة الإعداد الحالي. يتم بشكلٍ أساسي تحديد طريقة إدارة هذا الانتقال مع الحفاظ على التوافق في منطق الخدمة التي يمكن للمستخدم التحكّم فيها:

  1. أنشِئ إعدادًا جديدًا بالتعريف أو المفتاح أو الوحدة الجديدة المطلوبة.
  2. أوقِف الإعداد الحالي من خلال تسجيله للتوافق. استخدِم هذا الإعداد الجديد عند تطوير عملاء جدد.
  3. ننصح العملاء الجدد بتنفيذ منطق التوافق ضمن منطق الأعمال للخدمة التي يمكن للمستخدم التحكّم فيها.

يجب أن يضمن تنفيذ RequestSettingsChange للخدمة أنّ تغيير إعداد واحد ينعكس في الإعداد المقابل الذي تم إيقافه، وأنّ تغيير الإعداد المقابل ينعكس في الإعداد.

مثال على منطق التوافق:

  1. توقف خدمة عن استخدام الإعداد القديم TEMPERATURE_C (درجة مئوية) وتُدخل TEMPERATURE_K (كلفن).

  2. عندما يرسل الوكيل طلبًا لتعديل الإعداد الجديد:

    • تتلقّى الخدمة طلبًا لـ TEMPERATURE_K (على سبيل المثال، 295.15 كلفن).

    • يحوّل منطق الخدمة هذا إلى درجة مئوية (22 درجة مئوية) ويعدِّل ويحفظ كلا القيمتَين داخليًا للحفاظ على الاتساق للعملاء القدامى.

  3. عندما يرسل الوكيل طلبًا للإعداد الذي تم إيقافه من عميل قديم:

    • تتلقّى الخدمة طلبًا لـ TEMPERATURE_C (على سبيل المثال، 24 درجة مئوية).
    • تحوّل الخدمة هذا إلى كلفن (297.15 كلفن) وتعدِّل وتحفظ كلا القيمتَين داخليًا.

تضمن استراتيجية الكتابة المزدوجة هذه أنّ جميع العملاء، بغض النظر عن جدول الإصدار، يقرأون بيانات متسقة ودقيقة، ما يتجنّب الأعطال الناتجة عن حالات عدم تطابق الإصدارات الخارجية.

تنفيذ عميل

لتنفيذ عميل (على سبيل المثال، واجهة تفاعل بين الإنسان والآلة) يتفاعل مع وكيل "الإعدادات المفضّلة للمستخدم":

  1. حدِّد حزمة خدمات العميل للتفاعل مع واجهات معيّنة من "الإعدادات المفضّلة للمستخدم". في ملف VSIDL:

    • بصفتك خادمًا، نفِّذ com.sdv.google.user_preferences.view.ChangeNotifier للسماح للوكيل بإرسال إشعارات في الوقت الفعلي إلى العميل بشأن تغييرات الإعدادات.
    • بصفتك عميلاً، استخدِم com.sdv.google.user_preferences.UserPreferencesManagementService لطلب تعديلات الإعدادات والاشتراك في التحديثات.
    • بصفتك عميلاً، استخدِم com.sdv.google.user_preferences.UserPreferencesAdminService لإدارة الملفات الشخصية للمستخدمين (على سبيل المثال، الإنشاء والاختيار والحذف وإعادة الضبط إلى الإعدادات الأصلية).

    يوضّح المثال التالي ملف service_bundle.vsidl لعميل:

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

    أضِف سياسات التفويض وفقًا لذلك. للسماح بالتواصل مع وكيل "الإعدادات المفضّلة للمستخدم"، أنشِئ عميلاً للخوادم المحدّدة. على سبيل المثال:

    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. يمكنك تغيير إعدادات طلب التغيير في UserPreferencesManagementService:

    1. اتّصِل بـ UserPreferencesManagementService.
    2. أنشِئ مثيلاً من RequestSettingsChangeRequest، مع تحديد SettingsGroupId والإعدادات المطلوبة.
    3. اختياريّ. اضبط ChangePersistencePolicy على PERSISTENT_CHANGE (تلقائي) أو NON_PERSISTENT_CHANGE.
    4. نفِّذ RequestSettingsChange().

    المثال التالي مكتوب بلغة Rust المفاهيمية:

    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. اشترِك في تغييرات الإعدادات باستخدام user_preferences_management_service.proto وchange_notifier.proto:

    1. نفِّذ طلب الإجراء عن بُعد OnSettingsChange من واجهة ChangeNotifier ضمن حزمة الخدمات. يستدعي وكيل "الإعدادات المفضّلة للمستخدم" هذه الطريقة عند حدوث تغيير.
    2. اتّصِل بـ UserPreferencesManagementService.
    3. أنشِئ SubscribeToSettingsChangeAndGetSettingsRequest مع تحديد SettingsGroupId التي تريد مراقبتها.
    4. لعرض حالة الإعدادات ثم إرسال التحديثات المستقبلية من خلال تنفيذ OnSettingsChange، نفِّذ SubscribeToSettingsChangeAndGetSettings().

    المثال التالي لتنفيذ واجهة ChangeNotifier مكتوب بلغة Rust المفاهيمية:

    #[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())
        }
    }
    

    المثال التالي للاشتراك مكتوب بلغة Rust المفاهيمية:

    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. اختياري: يمكن للعملاء الذين يديرون الملفات الشخصية للمستخدمين (على سبيل المثال، تطبيق إعدادات مخصّص) استخدام user_preferences_admin_service.proto للتفاعل مع خدمة المشرف:

    1. اتّصِل بـ UserPreferencesAdminService.
    2. استخدِم طلبات الإجراء عن بُعد، مثل CreateUser وSelectUser وDeleteUser وFactoryReset وListUsers، لإدارة الملفات الشخصية للمستخدمين.

    المثال التالي لإنشاء مستخدم مكتوب بلغة Rust المفاهيمية:

    admin_service_client.CreateUser(&CreateUserRequest {
        user: Some(User {
            id: 1,
            flags: UserFlags::DRIVER.value(),
            ..Default::default()
        }).into(),
        ..Default::default()
    }).await?;
    
  5. اكتشِف الإعدادات والمستخدمين المتاحين من خلال خدمة المشرف باستخدام user_preferences_admin_service.proto:

    1. احصل على قائمة بجميع المستخدمين المسجّلين من خلال تنفيذ ListUsers() على UserPreferencesAdminService.
    2. احصل على إعدادات مستخدم معيّن من خلال تنفيذ GetUserSettings(user_id) على UserPreferencesAdminService.

    المثال التالي لإدراج المستخدمين والحصول على الإعدادات مكتوب بلغة Rust المفاهيمية:

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

ملخّص التدفق

  1. يبدأ العميل ويتّصل بخدمتَي الإدارة والإشراف للوكيل.
  2. يكتشف العميل مجموعات الإعدادات ويشترك فيها ويعرض الحالة الأولية.
  3. يرسل العميل RequestSettingsChange إلى الوكيل.
  4. يرسل الوكيل إشعارًا OnSettingsChange إلى العميل يتضمّن الإعدادات والحالة المعدَّلتَين.

للاطّلاع على مثال عمل كامل، راجِع HMIService في @samples/user_preferences/v1/.

تنفيذ الوكيل

تنفِّذ حزمة خدمات تم إطلاقها من خلال المنسّق وكيل "الإعدادات المفضّلة للمستخدم". لراحتك، يتم توفير تنفيذ مرجعي.

بالإضافة إلى ذلك، يتم توفير ملف user_preferences_sample.vsidl لحزمة الخدمات النموذجية هذه للوكيل:

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

يمكن أن يستخدم التنفيذ البرامج الوسيطة التي تم إنشاؤها ويجب أن يتم تجميعه في rust_ffi_shared تشير إليه حزمة الخدمات التي تنفِّذ وكيل "الإعدادات المفضّلة للمستخدم":

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

يتطلّب ملف سياسة تفويض العميل .textproto الأذونات اللازمة:

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
}

الملحق: المفاهيم الرئيسية

يصف هذا القسم بعض المفاهيم الرئيسية.

المستخدمون

يمكن لكل مستخدم مركبة (فئة User) إنشاء حساب يمكنه تخزين إعداداته المفضّلة فيه. لا تتيح "الإعدادات المفضّلة للمستخدم" الحسابات إلا لسائقي المركبات. يمكن للسائقين الضيوف إنشاء حسابات مؤقتة يتم حذفها تلقائيًا بعد استخدامها مرة واحدة.

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

مجموعات الإعدادات

تنظِّم مجموعات الإعدادات (فئة SettingsGroup) الإعدادات ذات الصلة وتديرها. يحدِّد كل مكوّن قابل للضبط داخل المركبة إعداداته كمجموعات، تتألف من قائمة بالإعدادات الممثلة كأزواج من المفاتيح والقيم. على سبيل المثال، يمكن للمركبات التي تحتوي على مقاعد كهربائية تحديد مجموعة إعدادات لمقعد السائق وأخرى لمقعد الراكب الأمامي، حيث تحتوي كلتا المجموعتَين على إعدادات تحمل الأسماء نفسها.

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

الإعدادات

يمثّل الإعداد، وهو رسالة (Setting فئة)، إعدادًا واحدًا ضمن SettingsGroup. تتألف هذه الرسالة من مفتاح، وهو اسم الإعداد، وقيمة يمكن أن تكون أحد أنواع متعددة.

يوضّح هذا المثال كيفية تمثيل إعداد بمفتاح وقيمة:

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

تعريفات الإعدادات

تعمل تعريفات الإعدادات (فئة SettingDefinition) كقوالب للإعدادات الفردية ضمن مجموعة إعدادات. تحدِّد هذه التعريفات الخصائص الأساسية للإعداد، مثل ما إذا كان الإعداد تتم مشاركته بين جميع المستخدمين أو خاصًا بكل مستخدم أو تتم إدارته خارجيًا (تمرير).

من المهم أيضًا أنّ تعريفات الإعدادات تحدِّد أيضًا أي قيود على قيمة الإعداد، مثل الحد الأدنى والحد الأقصى للقيم أو الزيادات المسموح بها أو مجموعة محدودة من الخيارات. تؤدي هذه القيود إلى الحفاظ على سلامة البيانات واتساقها لكل إعداد.

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

مثال على تسلسل الأحداث عندما يعدِّل المستخدم إعدادًا

يوضّح هذا المثال تسلسل الأحداث التي تحدث عندما يستخدم المستخدم نظام التشغيل Android Automotive OS (AAOS) لنظام المعلومات والترفيه داخل السيارة لتعديل إعداد:

الأحداث عند تغيير المستخدم
للإعداد

الشكل 1: الأحداث عند تغيير المستخدم لإعداد

مثال على تسلسل الأحداث عند بدء تشغيل مركبة

يوضّح هذا المثال كيف تطبِّق "الإعدادات المفضّلة للمستخدم" في SDV الإعدادات المفضّلة للمستخدم عند بدء تشغيل مركبة:

أحداث عند بدء تشغيل المركبة

الشكل 2: الأحداث عند بدء تشغيل مركبة