/* * Copyright (C) 2021 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 android.car.builtin.util; import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK; import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.ActivityManager; import android.car.builtin.annotation.AddedIn; import android.car.builtin.annotation.PlatformVersion; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; import com.android.internal.app.IVoiceInteractionSessionListener; import com.android.internal.app.IVoiceInteractionSessionShowCallback; import java.util.Objects; /** * Class to wrap {@link AssistUtils}. * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class AssistUtilsHelper { private static final String TAG = AssistUtilsHelper.class.getSimpleName(); @VisibleForTesting @AddedIn(PlatformVersion.TIRAMISU_0) static final String EXTRA_CAR_PUSH_TO_TALK = "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK"; /** * Determines if there is a voice interaction session running. * * @param context used to build the assist utils. * @return {@code true} if a session is running, {@code false} otherwise. */ @AddedIn(PlatformVersion.TIRAMISU_0) public static boolean isSessionRunning(@NonNull Context context) { AssistUtils assistUtils = getAssistUtils(context); return assistUtils.isSessionRunning(); } /** * Hides the current voice interaction session running * * @param context used to build the assist utils. */ @AddedIn(PlatformVersion.TIRAMISU_0) public static void hideCurrentSession(@NonNull Context context) { AssistUtils assistUtils = getAssistUtils(context); assistUtils.hideCurrentSession(); } /** * Registers a listener to monitor when the voice sessions are shown or hidden. * * @param context used to build the assist utils. * @param sessionListener listener that will receive shown or hidden voice sessions callback. */ // TODO(b/221604866) : Add unregister method @AddedIn(PlatformVersion.TIRAMISU_0) public static void registerVoiceInteractionSessionListenerHelper(@NonNull Context context, @NonNull VoiceInteractionSessionListenerHelper sessionListener) { Objects.requireNonNull(sessionListener, "Session listener must not be null."); AssistUtils assistUtils = getAssistUtils(context); assistUtils.registerVoiceInteractionSessionListener( new InternalVoiceInteractionSessionListener(sessionListener)); } /** * Shows the {@link android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK} * session for active service, if the assistant component is active for the current user. * * @return whether the assistant component is active for the current user. */ @AddedIn(PlatformVersion.TIRAMISU_0) public static boolean showPushToTalkSessionForActiveService(@NonNull Context context, @NonNull VoiceInteractionSessionShowCallbackHelper callback) { Objects.requireNonNull(callback, "On shown callback must not be null."); AssistUtils assistUtils = getAssistUtils(context); int currentUserId = ActivityManager.getCurrentUser(); if (assistUtils.getAssistComponentForUser(currentUserId) == null) { Slogf.d(TAG, "showPushToTalkSessionForActiveService(): no component for user %d", currentUserId); return false; } Bundle args = new Bundle(); args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true); IVoiceInteractionSessionShowCallback callbackWrapper = new InternalVoiceInteractionSessionShowCallback(callback); return assistUtils.showSessionForActiveService(args, SHOW_SOURCE_PUSH_TO_TALK, callbackWrapper, /* activityToken= */ null); } private static AssistUtils getAssistUtils(@NonNull Context context) { Objects.requireNonNull(context, "Context must not be null."); return new AssistUtils(context); } /** * See {@link IVoiceInteractionSessionShowCallback} */ public interface VoiceInteractionSessionShowCallbackHelper { /** * See {@link IVoiceInteractionSessionShowCallback#onFailed()} */ @AddedIn(PlatformVersion.TIRAMISU_1) void onFailed(); /** * See {@link IVoiceInteractionSessionShowCallback#onShow()} */ @AddedIn(PlatformVersion.TIRAMISU_1) void onShown(); } /** * See {@link IVoiceInteractionSessionListener} */ public interface VoiceInteractionSessionListenerHelper { /** * See {@link IVoiceInteractionSessionListener#onVoiceSessionShown()} */ @AddedIn(PlatformVersion.TIRAMISU_1) void onVoiceSessionShown(); /** * See {@link IVoiceInteractionSessionListener#onVoiceSessionHidden()} */ @AddedIn(PlatformVersion.TIRAMISU_1) void onVoiceSessionHidden(); } private static final class InternalVoiceInteractionSessionShowCallback extends IVoiceInteractionSessionShowCallback.Stub { private final VoiceInteractionSessionShowCallbackHelper mCallbackHelper; InternalVoiceInteractionSessionShowCallback( VoiceInteractionSessionShowCallbackHelper callbackHelper) { mCallbackHelper = callbackHelper; } @Override public void onFailed() { mCallbackHelper.onFailed(); } @Override public void onShown() { mCallbackHelper.onShown(); } } private static final class InternalVoiceInteractionSessionListener extends IVoiceInteractionSessionListener.Stub { private final VoiceInteractionSessionListenerHelper mListenerHelper; InternalVoiceInteractionSessionListener( VoiceInteractionSessionListenerHelper listenerHelper) { mListenerHelper = listenerHelper; } @Override public void onVoiceSessionShown() throws RemoteException { mListenerHelper.onVoiceSessionShown(); } @Override public void onVoiceSessionHidden() throws RemoteException { mListenerHelper.onVoiceSessionHidden(); } @Override public void onSetUiHints(Bundle args) throws RemoteException { Slogf.d(TAG, "onSetUiHints() not used"); } @Override public void onVoiceSessionWindowVisibilityChanged(boolean visible) throws RemoteException { Slogf.d(TAG, "onVoiceSessionWindowVisibilityChanged() not used"); } } private AssistUtilsHelper() { throw new UnsupportedOperationException("contains only static members"); } }