دستیار صوتی Tap-to-Read

Android Automotive صدا را جزء مهمی برای تعاملات ایمن رانندگی و یکی از ایمن‌ترین راه‌ها برای تعامل کاربران با سیستم‌عامل Android Automotive در حین رانندگی می‌داند. در نتیجه، ما APIهای دستیار صوتی Android (از جمله VoiceInteractionSession ) را گسترش دادیم تا دستیارهای صوتی را قادر سازد تا کارهایی را برای کاربران انجام دهند که انجام آنها در حین رانندگی دشوار است.

وقتی کاربر با اعلان‌های پیام تعامل دارد، «تپ برای خواندن» به دستیاران صوتی امکان می‌دهد پیام‌های متنی را از طرف کاربر بخوانند و به آن‌ها پاسخ دهند. برای ارائه این قابلیت، می توانید یک دستیار صوتی را با CarVoiceInteractionSession ادغام کنید.

در Automotive، اعلان‌های ارسال‌شده به مرکز اعلان‌هایی که به‌عنوان INBOX یا INBOX_IN_GROUP (مثلاً پیام‌های SMS) شناسایی می‌شوند، دارای دکمه پخش هستند. کاربر می تواند روی Play کلیک کند تا دستیار صوتی انتخاب شده اعلان را با صدای بلند بخواند و به صورت اختیاری به صورت صوتی پاسخ دهد.

اعلان ضربه زدن برای خواندن

شکل 1. اعلان ضربه زدن برای خواندن با دکمه Play.

ادغام با CarVoiceInteractionSession

بخش‌های بعدی نحوه ادغام دستیار صوتی با CarVoiceInteractionSession را شرح می‌دهند.

از تعاملات صوتی پشتیبانی کنید

برنامه‌هایی که خدمات تعامل صوتی خودرو را ارائه می‌کنند باید با تعاملات صوتی موجود اندروید یکپارچه شوند. برای کسب اطلاعات بیشتر، به Google Assistant برای Android (به استثنای VoiceInteractionSession ) مراجعه کنید. در حالی که همه عناصر API تعامل صوتی مانند آنچه در دستگاه‌های تلفن همراه پیاده‌سازی شده‌اند، باقی می‌مانند، CarVoiceInteractionSession (شرح شده در Implement CarVoiceInteractionSession ) جایگزین VoiceInteractionSession می‌شود. برای اطلاعات بیشتر به این صفحات مراجعه کنید:

CarVoiceInteractionSession را پیاده سازی کنید

CarVoiceInteractionSession API هایی را نشان می دهد که می توانید از آنها برای فعال کردن دستیارهای صوتی برای خواندن پیام های متنی با صدای بلند استفاده کنید و سپس از طرف کاربر به این پیام ها پاسخ دهید.

تفاوت اصلی بین کلاس‌های CarVoiceInteractionSession و VoiceInteractionSession در این است که CarVoiceInteractionSession در عمل در onShow عبور می‌کند، بنابراین دستیار صوتی می‌تواند به محض شروع جلسه CarVoiceInteractionSession ، زمینه درخواست کاربر را تشخیص دهد. پارامترهای onShow برای هر کلاس در جدول زیر آمده است:

CarVoiceInteractionSession جلسه تعامل صوتی
onShow این سه پارامتر را می گیرد:
  • args
  • showFlags
  • actions
onShow این دو پارامتر را می گیرد:
  • args
  • showFlags

تغییرات اندروید 10

با شروع اندروید 10، این پلتفرم VoiceInteractionService.onGetSupportedVoiceActions را فراخوانی می کند تا تشخیص دهد کدام عملکردها پشتیبانی می شوند. همانطور که در مثال زیر نشان داده شده است، دستیار صوتی VoiceInteractionService.onGetSupportedVoiceActions را لغو و پیاده سازی می کند:

public class MyInteractionService extends VoiceInteractionService {
    private static final List SUPPORTED_VOICE_ACTIONS = Arrays.asList(
        CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION);

    @Override
    public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) {
       Set result = new HashSet<>(voiceActions);
       result.retainAll(SUPPORTED_VOICE_ACTIONS);
       return result;
   }
}

اقدامات معتبر در جدول زیر توضیح داده شده است. برای جزئیات در مورد هر عمل، نمودارهای توالی را ببینید.

عمل بار مورد انتظار عملکرد تعامل صوتی مورد انتظار
VOICE_ACTION_READ_NOTIFICATION پیام‌ها را با صدای بلند برای کاربر بخوانید و پس از خواندن موفقیت‌آمیز پیام‌ها، علامت‌گذاری به‌عنوان خوانده‌شده در انتظار را بازگردانید. در صورت تمایل، از کاربر بخواهید که پاسخ دهد.
VOICE_ACTION_REPLY_NOTIFICATION قابل حمل با کلید
KEY_NOTIFICATION که به StatusBarNotification نگاشت می شود.
به android.permission.BIND_NOTIFICATION_LISTENER_SERVICE نیاز دارد.
از کاربر بخواهید که پیام پاسخ را بیان کند، پیام پاسخ را در RemoteInputReply هدف معلق وارد کند، و سپس هدف معلق را روشن کند.
VOICE_ACTION_HANDLE_EXCEPTION رشته با کلید.
KEY_EXCEPTION که به ExceptionValue (شرح شده در مقادیر Exception ) نگاشت می شود.
KEY_FALLBACK_ASSISTANT_ENABLED که به یک مقدار بولی نگاشت می شود. اگر مقدار true باشد، دستیار بازگشتی که می‌تواند درخواست کاربر را رسیدگی کند غیرفعال شده است.
اقدام مورد انتظاری که برای استثنا انجام می شود در مستندات استثنا تعریف شده است.

مقادیر استثنایی

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING به دستیار صوتی نشان می دهد که مجوز Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE و دریافت این مجوز را از کاربر ندارد.

درخواست مجوز شنونده اعلان

اگر دستیار صوتی پیش‌فرض مجوز شنونده اعلان را نداشته باشد، FallbackAssistant پلتفرم (در صورت فعال بودن توسط سازنده خودرو) ممکن است قبل از اینکه به دستیار صوتی برای درخواست مجوز اطلاع داده شود، پیام را با صدای بلند بخواند. برای تعیین اینکه آیا FallbackAssistant فعال است و پیام را خوانده است، دستیار صوتی باید مقدار بولی KEY_FALLBACK_ASSISTANT_ENABLED را در بار بررسی کند.

این پلتفرم به دستیار صوتی توصیه می‌کند منطق محدودکننده نرخ را برای تعداد دفعاتی که این مجوز درخواست می‌شود، اضافه کند. انجام این کار به کاربری احترام می‌گذارد که نمی‌خواهد این مجوز را به دستیار صوتی بدهد و FallbackAssistant را برای خواندن پیام‌های متنی با صدای بلند ترجیح می‌دهد. درخواست اجازه از کاربر هر بار که کاربر Play را روی یک اعلان پیام فشار می دهد، می تواند یک تجربه منفی برای کاربر باشد. این پلتفرم از طرف دستیار صوتی محدودیت نرخ اعمال نمی کند.

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

با StatusBarNotification کار کنید

StatusBarNotification که با عملکردهای صوتی خواندن و پاسخ ارسال می‌شود، همیشه در یک اعلان پیام‌رسانی سازگار با خودرو، همانطور که در اطلاع رسانی به کاربران پیام‌ها توضیح داده شده است، قرار می‌گیرد. در حالی که ممکن است برخی از اعلان‌ها دارای هدف «پاسخ در انتظار» نباشند، اما همه آن‌ها دارای اهداف معلق به عنوان خوانده شده علامت‌گذاری می‌شوند.

برای ساده‌سازی تعامل با اعلان‌ها، از NotificationPayloadHandler استفاده کنید، که روش‌هایی را برای استخراج پیام‌ها از اعلان و نوشتن پیام‌های پاسخ به هدف معلق اعلان ارائه می‌کند. پس از اینکه دستیار صوتی پیام را خواند، دستیار صوتی باید علامت را به عنوان هدف خواندن فعال کند.

پیش شرط های Tap-to-Read را برآورده کنید

فقط VoiceInteractionSession از دستیار صوتی پیش‌فرض زمانی که کاربر عمل صوتی را برای خواندن و پاسخ به پیام‌ها فعال می‌کند مطلع می‌شود. همانطور که در بالا ذکر شد، این دستیار صوتی پیش فرض باید مجوز شنونده اعلان را نیز داشته باشد.

نمودارهای توالی

این شکل‌ها جریان‌های منطقی CarVoiceInteractionSession actions را نشان می‌دهند:

VOICE_ACTION_READ_NOTIFICATION

شکل 2. نمودار توالی برای VOICE_ACTION_READ_NOTIFICATION.

در مورد شکل 3، برنامه محدودیت نرخ در درخواست های مجوز توصیه می شود:

VOICE_ACTION_REPLY_NOTIFICATION

شکل 3. نمودار توالی برای VOICE_ACTION_REPLY_NOTIFICATION.

VOICE_ACTION_HANDLE_EXCEPTION

شکل 4. نمودار توالی برای VOICE_ACTION_HANDLE_EXCEPTION.

خواندن نام برنامه

اگر می‌خواهید دستیار صوتی‌تان در حین خواندن پیام، نام برنامه پیام‌رسانی را با صدای بلند بخواند (برای مثال، «سام از Hangouts گفت...»)، عملکردی مانند آنچه در مثال کد زیر نشان داده شده است ایجاد کنید تا مطمئن شوید که دستیار در حال خواندن پیام‌ها است. نام صحیح:

@Nullable
String getMessageApplicationName(Context context, StatusBarNotification statusBarNotification) {
    ApplicationInfo info = getApplicationInfo(context, statusBarNotification.getPackageName());
    if (info == null) return null;

    Notification notification = statusBarNotification.getNotification();

    // Sometimes system packages will post on behalf of other apps, so check this
    // field for a system app notification.
    if (isSystemApp(info)
            && notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
        return notification.extras.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME);
    } else {
        PackageManager pm = context.getPackageManager();
        return String.valueOf(pm.getApplicationLabel(info));
    }
}

@Nullable
ApplicationInfo getApplicationInfo(Context context, String packageName) {
    final PackageManager pm = context.getPackageManager();
    ApplicationInfo info;
    try {
        info = pm.getApplicationInfo(packageName, 0);
    } catch (PackageManager.NameNotFoundException e) {
        return null;
    }
    return info;
}

boolean isSystemApp(ApplicationInfo info) {
    return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}