blob: cd5822913686208bba80c31165aece8c2b9b706a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.assist;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.service.notification.StatusBarNotification;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionSession;
import androidx.annotation.StringDef;
import com.android.car.assist.payloadhandlers.NotificationPayloadHandler;
/**
* An active voice interaction session on the car, providing additional actions which assistant
* should act on. Override the {@link #onShow(String, Bundle, int)} to received the action specified
* by the voice session initiator.
*/
public abstract class CarVoiceInteractionSession extends VoiceInteractionSession {
/** The key used for the action {@link String} in the payload {@link Bundle}. */
public static final String KEY_ACTION = "KEY_ACTION";
/**
* The key used for the {@link CarVoiceInteractionSession#VOICE_ACTION_HANDLE_EXCEPTION} payload
* {@link Bundle}. Must map to a {@link ExceptionValue}.
*/
public static final String KEY_EXCEPTION = "KEY_EXCEPTION";
/**
* The key used for the payload {@link Bundle}, if a {@link StatusBarNotification} is used as
* the payload.
*/
public static final String KEY_NOTIFICATION = "KEY_NOTIFICATION";
/** Indicates to assistant that no action was specified. */
public static final String VOICE_ACTION_NO_ACTION = "VOICE_ACTION_NO_ACTION";
/** Indicates to assistant that a read action is being requested for a given payload. */
public static final String VOICE_ACTION_READ_NOTIFICATION = "VOICE_ACTION_READ_NOTIFICATION";
/** Indicates to assistant that a reply action is being requested for a given payload. */
public static final String VOICE_ACTION_REPLY_NOTIFICATION = "VOICE_ACTION_REPLY_NOTIFICATION";
/**
* Indicates to assistant that it should resolve the exception in the given payload (found in
* {@link CarVoiceInteractionSession#KEY_EXCEPTION}'s value).
*/
public static final String VOICE_ACTION_HANDLE_EXCEPTION = "VOICE_ACTION_HANDLE_EXCEPTION";
/**
* The list of exceptions the active voice service must handle.
*/
@StringDef({EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING})
public @interface ExceptionValue {}
/**
* Indicates to assistant that it is missing the Notification Listener permission, and should
* request this permission from the user.
**/
public static final String EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING =
"EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING";
private final NotificationPayloadHandler mNotificationPayloadHandler;
public CarVoiceInteractionSession(Context context) {
super(context);
mNotificationPayloadHandler = new NotificationPayloadHandler(getContext());
}
public CarVoiceInteractionSession(Context context, Handler handler) {
super(context, handler);
mNotificationPayloadHandler = new NotificationPayloadHandler(getContext());
}
/**
* Returns the notification payload handler, which can be used to handle actions related to
* notification payloads.
*/
public NotificationPayloadHandler getNotificationPayloadHandler() {
return mNotificationPayloadHandler;
}
@Override
public final void onShow(Bundle args, int showFlags) {
super.onShow(args, showFlags);
if (args != null && isCarNotificationSource(showFlags)) {
String action = getRequestedVoiceAction(args);
if (!VOICE_ACTION_NO_ACTION.equals(action)) {
onShow(action, args, showFlags);
return;
}
}
onShow(VOICE_ACTION_NO_ACTION, args, showFlags);
}
/**
* Called when the session UI is going to be shown. This is called after
* {@link #onCreateContentView} (if the session's content UI needed to be created) and
* immediately prior to the window being shown. This may be called while the window
* is already shown, if a show request has come in while it is shown, to allow you to
* update the UI to match the new show arguments.
*
* @param action The action that is being requested for this session
* (e.g. {@link CarVoiceInteractionSession#VOICE_ACTION_READ_NOTIFICATION},
* {@link CarVoiceInteractionSession#VOICE_ACTION_REPLY_NOTIFICATION}).
* @param args The arguments that were supplied to
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
* @param flags The show flags originally provided to
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
*/
protected abstract void onShow(String action, Bundle args, int flags);
/**
* Returns true if the request was initiated for a car notification.
*/
private static boolean isCarNotificationSource(int flags) {
return (flags & SHOW_SOURCE_NOTIFICATION) != 0;
}
/**
* Returns the action {@link String} provided in the args {@Bundle},
* or {@link CarVoiceInteractionSession#VOICE_ACTION_NO_ACTION} if no such string was provided.
*/
protected static String getRequestedVoiceAction(Bundle args) {
return args.getString(KEY_ACTION, VOICE_ACTION_NO_ACTION);
}
}