1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.car.builtin.util; 18 19 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK; 20 21 import android.annotation.NonNull; 22 import android.annotation.SystemApi; 23 import android.app.ActivityManager; 24 import android.car.builtin.annotation.AddedIn; 25 import android.car.builtin.annotation.PlatformVersion; 26 import android.content.Context; 27 import android.os.Bundle; 28 import android.os.RemoteException; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.app.AssistUtils; 32 import com.android.internal.app.IVoiceInteractionSessionListener; 33 import com.android.internal.app.IVoiceInteractionSessionShowCallback; 34 35 import java.util.Objects; 36 37 /** 38 * Class to wrap {@link AssistUtils}. 39 * @hide 40 */ 41 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 42 public final class AssistUtilsHelper { 43 44 private static final String TAG = AssistUtilsHelper.class.getSimpleName(); 45 46 @VisibleForTesting 47 @AddedIn(PlatformVersion.TIRAMISU_0) 48 static final String EXTRA_CAR_PUSH_TO_TALK = 49 "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK"; 50 51 /** 52 * Determines if there is a voice interaction session running. 53 * 54 * @param context used to build the assist utils. 55 * @return {@code true} if a session is running, {@code false} otherwise. 56 */ 57 @AddedIn(PlatformVersion.TIRAMISU_0) isSessionRunning(@onNull Context context)58 public static boolean isSessionRunning(@NonNull Context context) { 59 AssistUtils assistUtils = getAssistUtils(context); 60 61 return assistUtils.isSessionRunning(); 62 } 63 64 /** 65 * Hides the current voice interaction session running 66 * 67 * @param context used to build the assist utils. 68 */ 69 @AddedIn(PlatformVersion.TIRAMISU_0) hideCurrentSession(@onNull Context context)70 public static void hideCurrentSession(@NonNull Context context) { 71 AssistUtils assistUtils = getAssistUtils(context); 72 73 assistUtils.hideCurrentSession(); 74 } 75 76 /** 77 * Registers a listener to monitor when the voice sessions are shown or hidden. 78 * 79 * @param context used to build the assist utils. 80 * @param sessionListener listener that will receive shown or hidden voice sessions callback. 81 */ 82 // TODO(b/221604866) : Add unregister method 83 @AddedIn(PlatformVersion.TIRAMISU_0) registerVoiceInteractionSessionListenerHelper(@onNull Context context, @NonNull VoiceInteractionSessionListenerHelper sessionListener)84 public static void registerVoiceInteractionSessionListenerHelper(@NonNull Context context, 85 @NonNull VoiceInteractionSessionListenerHelper sessionListener) { 86 Objects.requireNonNull(sessionListener, "Session listener must not be null."); 87 88 AssistUtils assistUtils = getAssistUtils(context); 89 90 assistUtils.registerVoiceInteractionSessionListener( 91 new InternalVoiceInteractionSessionListener(sessionListener)); 92 } 93 94 /** 95 * Shows the {@link android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK} 96 * session for active service, if the assistant component is active for the current user. 97 * 98 * @return whether the assistant component is active for the current user. 99 */ 100 @AddedIn(PlatformVersion.TIRAMISU_0) showPushToTalkSessionForActiveService(@onNull Context context, @NonNull VoiceInteractionSessionShowCallbackHelper callback)101 public static boolean showPushToTalkSessionForActiveService(@NonNull Context context, 102 @NonNull VoiceInteractionSessionShowCallbackHelper callback) { 103 Objects.requireNonNull(callback, "On shown callback must not be null."); 104 105 AssistUtils assistUtils = getAssistUtils(context); 106 int currentUserId = ActivityManager.getCurrentUser(); 107 108 109 if (assistUtils.getAssistComponentForUser(currentUserId) == null) { 110 Slogf.d(TAG, "showPushToTalkSessionForActiveService(): no component for user %d", 111 currentUserId); 112 return false; 113 } 114 115 Bundle args = new Bundle(); 116 args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true); 117 118 IVoiceInteractionSessionShowCallback callbackWrapper = 119 new InternalVoiceInteractionSessionShowCallback(callback); 120 121 return assistUtils.showSessionForActiveService(args, SHOW_SOURCE_PUSH_TO_TALK, 122 callbackWrapper, /* activityToken= */ null); 123 } 124 getAssistUtils(@onNull Context context)125 private static AssistUtils getAssistUtils(@NonNull Context context) { 126 Objects.requireNonNull(context, "Context must not be null."); 127 return new AssistUtils(context); 128 } 129 130 /** 131 * See {@link IVoiceInteractionSessionShowCallback} 132 */ 133 public interface VoiceInteractionSessionShowCallbackHelper { 134 /** 135 * See {@link IVoiceInteractionSessionShowCallback#onFailed()} 136 */ 137 @AddedIn(PlatformVersion.TIRAMISU_1) onFailed()138 void onFailed(); 139 140 /** 141 * See {@link IVoiceInteractionSessionShowCallback#onShow()} 142 */ 143 @AddedIn(PlatformVersion.TIRAMISU_1) onShown()144 void onShown(); 145 } 146 147 /** 148 * See {@link IVoiceInteractionSessionListener} 149 */ 150 public interface VoiceInteractionSessionListenerHelper { 151 152 /** 153 * See {@link IVoiceInteractionSessionListener#onVoiceSessionShown()} 154 */ 155 @AddedIn(PlatformVersion.TIRAMISU_1) onVoiceSessionShown()156 void onVoiceSessionShown(); 157 158 /** 159 * See {@link IVoiceInteractionSessionListener#onVoiceSessionHidden()} 160 */ 161 @AddedIn(PlatformVersion.TIRAMISU_1) onVoiceSessionHidden()162 void onVoiceSessionHidden(); 163 } 164 165 private static final class InternalVoiceInteractionSessionShowCallback extends 166 IVoiceInteractionSessionShowCallback.Stub { 167 private final VoiceInteractionSessionShowCallbackHelper mCallbackHelper; 168 InternalVoiceInteractionSessionShowCallback( VoiceInteractionSessionShowCallbackHelper callbackHelper)169 InternalVoiceInteractionSessionShowCallback( 170 VoiceInteractionSessionShowCallbackHelper callbackHelper) { 171 mCallbackHelper = callbackHelper; 172 } 173 174 @Override onFailed()175 public void onFailed() { 176 mCallbackHelper.onFailed(); 177 } 178 179 @Override onShown()180 public void onShown() { 181 mCallbackHelper.onShown(); 182 } 183 } 184 185 private static final class InternalVoiceInteractionSessionListener extends 186 IVoiceInteractionSessionListener.Stub { 187 188 private final VoiceInteractionSessionListenerHelper mListenerHelper; 189 InternalVoiceInteractionSessionListener( VoiceInteractionSessionListenerHelper listenerHelper)190 InternalVoiceInteractionSessionListener( 191 VoiceInteractionSessionListenerHelper listenerHelper) { 192 mListenerHelper = listenerHelper; 193 } 194 195 @Override onVoiceSessionShown()196 public void onVoiceSessionShown() throws RemoteException { 197 mListenerHelper.onVoiceSessionShown(); 198 } 199 200 @Override onVoiceSessionHidden()201 public void onVoiceSessionHidden() throws RemoteException { 202 mListenerHelper.onVoiceSessionHidden(); 203 } 204 205 @Override onSetUiHints(Bundle args)206 public void onSetUiHints(Bundle args) throws RemoteException { 207 Slogf.d(TAG, "onSetUiHints() not used"); 208 } 209 210 @Override onVoiceSessionWindowVisibilityChanged(boolean visible)211 public void onVoiceSessionWindowVisibilityChanged(boolean visible) 212 throws RemoteException { 213 Slogf.d(TAG, "onVoiceSessionWindowVisibilityChanged() not used"); 214 } 215 } 216 AssistUtilsHelper()217 private AssistUtilsHelper() { 218 throw new UnsupportedOperationException("contains only static members"); 219 } 220 } 221