• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.os.SystemClock;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.internal.app.AssistUtils;
33 import com.android.internal.app.IVoiceInteractionSessionListener;
34 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
35 
36 import java.util.Objects;
37 
38 /**
39  * Class to wrap {@link AssistUtils}.
40  * @hide
41  */
42 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
43 public final class AssistUtilsHelper {
44 
45     private static final String TAG = AssistUtilsHelper.class.getSimpleName();
46 
47     /**
48      * Used as a boolean extra field on show the session for the currently active voice interaction
49      * service, {@code true} indicates that the service was launch from a key event,
50      * {@code false} otherwise.
51      */
52     @VisibleForTesting
53     static final String EXTRA_CAR_PUSH_TO_TALK =
54             "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
55 
56     /**
57      * Used as a long extra field on show the session for the currently active voice interaction
58      * service, the value indicates the button press time measured in milliseconds since the last
59      * boot up.
60      */
61     @VisibleForTesting
62     static final String EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS =
63             "com.android.car.input.EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS";
64 
65     /**
66      * Determines if there is a voice interaction session running.
67      *
68      * @param context used to build the assist utils.
69      * @return {@code true} if a session is running, {@code false} otherwise.
70      */
71     @AddedIn(PlatformVersion.TIRAMISU_0)
isSessionRunning(@onNull Context context)72     public static boolean isSessionRunning(@NonNull Context context) {
73         AssistUtils assistUtils = getAssistUtils(context);
74 
75         return assistUtils.isSessionRunning();
76     }
77 
78     /**
79      * Hides the current voice interaction session running
80      *
81      * @param context used to build the assist utils.
82      */
83     @AddedIn(PlatformVersion.TIRAMISU_0)
hideCurrentSession(@onNull Context context)84     public static void hideCurrentSession(@NonNull Context context) {
85         AssistUtils assistUtils = getAssistUtils(context);
86 
87         assistUtils.hideCurrentSession();
88     }
89 
90     /**
91      * Registers a listener to monitor when the voice sessions are shown or hidden.
92      *
93      * @param context used to build the assist utils.
94      * @param sessionListener listener that will receive shown or hidden voice sessions callback.
95      */
96     // TODO(b/221604866) : Add unregister method
97     @AddedIn(PlatformVersion.TIRAMISU_0)
registerVoiceInteractionSessionListenerHelper(@onNull Context context, @NonNull VoiceInteractionSessionListenerHelper sessionListener)98     public static void registerVoiceInteractionSessionListenerHelper(@NonNull Context context,
99             @NonNull VoiceInteractionSessionListenerHelper sessionListener) {
100         Objects.requireNonNull(sessionListener, "Session listener must not be null.");
101 
102         AssistUtils assistUtils = getAssistUtils(context);
103 
104         assistUtils.registerVoiceInteractionSessionListener(
105                 new InternalVoiceInteractionSessionListener(sessionListener));
106     }
107 
108     /**
109      * Shows the {@link android.service.voice.VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK}
110      * session for active service, if the assistant component is active for the current user.
111      *
112      * @return whether the assistant component is active for the current user.
113      */
114     @AddedIn(PlatformVersion.TIRAMISU_0)
showPushToTalkSessionForActiveService(@onNull Context context, @NonNull VoiceInteractionSessionShowCallbackHelper callback)115     public static boolean showPushToTalkSessionForActiveService(@NonNull Context context,
116             @NonNull VoiceInteractionSessionShowCallbackHelper callback) {
117         Objects.requireNonNull(callback, "On shown callback must not be null.");
118 
119         AssistUtils assistUtils = getAssistUtils(context);
120         int currentUserId = ActivityManager.getCurrentUser();
121 
122 
123         if (assistUtils.getAssistComponentForUser(currentUserId) == null) {
124             Slogf.d(TAG, "showPushToTalkSessionForActiveService(): no component for user %d",
125                     currentUserId);
126             return false;
127         }
128 
129         Bundle args = new Bundle();
130         args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true);
131         args.putLong(EXTRA_TRIGGER_TIMESTAMP_PUSH_TO_TALK_MS, SystemClock.elapsedRealtime());
132 
133         IVoiceInteractionSessionShowCallback callbackWrapper =
134                 new InternalVoiceInteractionSessionShowCallback(callback);
135 
136         return assistUtils.showSessionForActiveService(args, SHOW_SOURCE_PUSH_TO_TALK,
137                 callbackWrapper, /* activityToken= */ null);
138     }
139 
getAssistUtils(@onNull Context context)140     private static AssistUtils getAssistUtils(@NonNull Context context) {
141         Objects.requireNonNull(context, "Context must not be null.");
142         return new AssistUtils(context);
143     }
144 
145     /**
146      * See {@link IVoiceInteractionSessionShowCallback}
147      */
148     public interface VoiceInteractionSessionShowCallbackHelper {
149         /**
150          * See {@link IVoiceInteractionSessionShowCallback#onFailed()}
151          */
152         @AddedIn(PlatformVersion.TIRAMISU_1)
onFailed()153         void onFailed();
154 
155         /**
156          * See {@link IVoiceInteractionSessionShowCallback#onShow()}
157          */
158         @AddedIn(PlatformVersion.TIRAMISU_1)
onShown()159         void onShown();
160     }
161 
162     /**
163      * See {@link IVoiceInteractionSessionListener}
164      */
165     public interface VoiceInteractionSessionListenerHelper {
166 
167         /**
168          * See {@link IVoiceInteractionSessionListener#onVoiceSessionShown()}
169          */
170         @AddedIn(PlatformVersion.TIRAMISU_1)
onVoiceSessionShown()171         void onVoiceSessionShown();
172 
173         /**
174          * See {@link IVoiceInteractionSessionListener#onVoiceSessionHidden()}
175          */
176         @AddedIn(PlatformVersion.TIRAMISU_1)
onVoiceSessionHidden()177         void onVoiceSessionHidden();
178     }
179 
180     private static final class InternalVoiceInteractionSessionShowCallback extends
181             IVoiceInteractionSessionShowCallback.Stub {
182         private final VoiceInteractionSessionShowCallbackHelper mCallbackHelper;
183 
InternalVoiceInteractionSessionShowCallback( VoiceInteractionSessionShowCallbackHelper callbackHelper)184         InternalVoiceInteractionSessionShowCallback(
185                 VoiceInteractionSessionShowCallbackHelper callbackHelper) {
186             mCallbackHelper = callbackHelper;
187         }
188 
189         @Override
onFailed()190         public void onFailed() {
191             mCallbackHelper.onFailed();
192         }
193 
194         @Override
onShown()195         public void onShown() {
196             mCallbackHelper.onShown();
197         }
198     }
199 
200     private static final class InternalVoiceInteractionSessionListener extends
201             IVoiceInteractionSessionListener.Stub {
202 
203         private final VoiceInteractionSessionListenerHelper mListenerHelper;
204 
InternalVoiceInteractionSessionListener( VoiceInteractionSessionListenerHelper listenerHelper)205         InternalVoiceInteractionSessionListener(
206                 VoiceInteractionSessionListenerHelper listenerHelper) {
207             mListenerHelper = listenerHelper;
208         }
209 
210         @Override
onVoiceSessionShown()211         public void onVoiceSessionShown() throws RemoteException {
212             mListenerHelper.onVoiceSessionShown();
213         }
214 
215         @Override
onVoiceSessionHidden()216         public void onVoiceSessionHidden() throws RemoteException {
217             mListenerHelper.onVoiceSessionHidden();
218         }
219 
220         @Override
onSetUiHints(Bundle args)221         public void onSetUiHints(Bundle args) throws RemoteException {
222             Slogf.d(TAG, "onSetUiHints() not used");
223         }
224 
225         @Override
onVoiceSessionWindowVisibilityChanged(boolean visible)226         public void onVoiceSessionWindowVisibilityChanged(boolean visible)
227                 throws RemoteException {
228             Slogf.d(TAG, "onVoiceSessionWindowVisibilityChanged() not used");
229         }
230     }
231 
AssistUtilsHelper()232     private AssistUtilsHelper() {
233         throw new UnsupportedOperationException("contains only static members");
234     }
235 }
236