음성 어시스턴트 탭하여 읽기

Android Automotive는 음성을 안전 운전 상호작용을 가능하게 하는 중요한 구성요소이자 사용자가 운전 중에 Android Automotive OS와 상호작용할 수 있는 가장 안전한 방법 중 하나로 간주합니다. 따라서 사용자가 운전 중에 하기 어려울 수 있는 작업을 음성 어시스턴트가 실행할 수 있도록 기존 Android Voice Assistant API(VoiceInteractionSession 포함)를 확장했습니다.

탭하여 읽기를 사용하면 사용자가 메시지 알림과 상호작용할 때 음성 어시스턴트가 사용자를 대신하여 문자 메시지를 읽고 답장할 수 있습니다. 이 기능을 제공하기 위해 음성 어시스턴트를 CarVoiceInteractionSession과 통합할 수 있습니다.

탭하여 읽는 알림

Automotive에서 INBOX 또는 INBOX_IN_GROUP 알림(예: SMS 메시지)으로 식별되며 알림 센터에 게시되는 알림에는 재생 작업 버튼이 포함됩니다. 사용자가 이 버튼을 사용하면 선택된 VIA에서 알림을 소리 내어 읽고 선택적으로 음성으로 답장할 수 있습니다.

그림 1. 탭하여 읽는 알림

CarVoiceInteractionSession과 통합

1. VoiceInteractions 후원

자동차 음성 상호작용 서비스를 제공하는 애플리케이션은 기존 Android 음성 상호작용반드시 통합되어야합니다(VoiceInteractionSession 제외). 음성 상호작용 API의 다른 모든 구성요소는 휴대기기에서 구현된 것과 동일하게 유지되지만, CarVoiceInteractionSession(아래에서 설명)은 VoiceInteractionSession을 대체합니다. 자세한 내용은 다음 자료를 참고하세요.

2. CarVoiceInteractionSession 구현

CarVoiceInteractionSession은 음성 어시스턴트가 사용자를 대신하여 문자 메시지를 소리 내어 읽은 후 답장할 수 있도록 하는 데 사용할 수 있는 API를 노출합니다.

CarVoiceInteractionSessionVoiceInteractionSession을 비교할 때 주요 차이점은 CarVoiceInteractionSessiononShow의 작업을 전달하므로 CarVoiceInteractionSession이 세션을 시작하는 즉시 음성 어시스턴트가 사용자 요청의 맥락을 감지할 수 있다는 점입니다.

CarVoiceInteractionSession VoiceInteractionSession
onShow는 다음 세 가지 매개변수를 사용합니다.
  • args
  • showFlags
  • actions
onShow는 다음 두 가지 매개변수를 사용합니다.
  • args
  • showFlags

Android 10 변경사항

Android 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 키가 있는 Parcelable입니다.
StatusBarNotification에 매핑되는 KEY_NOTIFICATION입니다.
android.permission.BIND_NOTIFICATION_LISTENER_SERVICE가 필요합니다.
사용자에게 답장 메시지를 말하도록 요청하고 대기 중 인텐트의 RemoteInputReply에 답장 메시지를 입력한 후 대기 중 인텐트를 실행합니다.
VOICE_ACTION_HANDLE_EXCEPTION 키가 있는 문자열입니다.
ExceptionValue(아래에 설명)에 매핑되는 KEY_EXCEPTION입니다.
부울 값 값에 매핑되는 KEY_FALLBACK_ASSISTANT_ENABLED입니다. 값이 true이면 사용자의 요청을 처리할 수 있는 대체 어시스턴트가 사용 중지된 것입니다.
예외와 관련하여 실행해야 할 예상 작업은 예외에 관한 문서에 정의됩니다.

ExceptionValue

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING은 음성 어시스턴트에 Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE 권한이 없음을 나타내며 사용자로부터 이 권한을 얻도록 합니다.

3. 알림 리스너 권한 요청

기본 음성 어시스턴트에 알림 리스너 권한이 없다면 플랫폼의 FallbackAssistant(자동차 제조업체에서 사용 설정한 경우)는 음성 어시스턴트가 권한을 요청하라는 알림을 받기 전에 메시지를 소리 내어 읽을 수 있습니다. FallbackAssistant가 사용 설정되어 있어 메시지를 읽었는지 확인하려면 음성 어시스턴트가 페이로드의 KEY_FALLBACK_ASSISTANT_ENABLED 부울 값을 확인해야 합니다.

플랫폼에서는 음성 어시스턴트가 이 권한이 요청되는 횟수와 관련하여 비율 제한 로직을 추가할 것을 권장합니다. 비율 제한 로직을 추가하면 음성 어시스턴트에 이 권한을 부여하지 않으려는 사용자를 존중하고 FallbackAssistant가 문자 메시지를 소리 내어 읽는 것을 선호하게 됩니다. 사용자가 메시지 알림 시 재생을 누를 때마다 이 사용자에게 권한을 요청하면 부정적인 사용자 경험을 초래할 수 있습니다. 플랫폼은 음성 어시스턴트를 대신하여 비율 제한을 부과하지 않습니다.

알림 리스너 권한을 요청할 때 음성 어시스턴트는 CarUxRestrictionsManager 를 사용하여 사용자가 주차했는지 또는 운전 중인지 확인해야 합니다. 사용자가 운전 중이면 음성 어시스턴트는 권한 부여 방법에 관한 안내를 제공하는 알림을 표시합니다. 이렇게 하면 사용자가 더 안전할 때, 권한을 부여하는 데 도움이 됩니다. 그리고 권한을 부여하도록 사용자에게 알려줍니다.

4. StatusBarNotification 사용

읽기 및 답장 음성 작업으로 전달된 StatusBarNotifications사용자에게 메시지 알림에 설명된 대로 항상 '자동차 호환 메시지 알림'에 있습니다. 일부 알림에는 답장 대기 중 인텐트가 없을 수 있지만 모든 알림에는 읽음으로 표시 대기 중 인텐트가 있습니다.

알림과의 상호작용을 간소화하려면 알림에서 메시지를 추출하고 알림의 적절한 대기 중 인텐트에 답장 메시지를 작성하는 메서드를 제공하는 NotificationPayloadHandler를 사용합니다. 음성 어시스턴트가 메시지를 읽은 이후 음성 어시스턴트는 읽음으로 표시 인텐트를 실행해야 합니다.

5 탭하여 읽기 사전 조건 충족

사용자가 음성 작업을 트리거하여 메시지를 읽고 답장할 때 기본 음성 어시스턴트의 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의 시퀀스 다이어그램

도움말 및 유용한 정보

애플리케이션 이름 읽기

음성 어시스턴트가 메시지를 읽는 동안 메시지 애플리케이션의 이름을 소리 내어 읽도록 하려면(즉, "행아웃의 샘이 말하기를...") 아래와 같은 함수를 만들어 정확한 이름을 소리 내어 읽는지 확인해야 합니다.

@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 applications, so check this
    // field for a system application 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;
}