1 /*
2  * Copyright (C) 2015 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 com.android.internal.app;
18 
19 import android.annotation.NonNull;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageManager;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.provider.Settings;
30 import android.util.Log;
31 
32 import java.util.ArrayList;
33 import java.util.Set;
34 
35 /**
36  * Utility method for dealing with the assistant aspects of
37  * {@link com.android.internal.app.IVoiceInteractionManagerService IVoiceInteractionManagerService}.
38  */
39 public class AssistUtils {
40 
41     private static final String TAG = "AssistUtils";
42 
43     private final Context mContext;
44     private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
45 
46     @UnsupportedAppUsage
AssistUtils(Context context)47     public AssistUtils(Context context) {
48         mContext = context;
49         mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface(
50                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
51     }
52 
showSessionForActiveService(Bundle args, int sourceFlags, IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken)53     public boolean showSessionForActiveService(Bundle args, int sourceFlags,
54             IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
55         try {
56             if (mVoiceInteractionManagerService != null) {
57                 return mVoiceInteractionManagerService.showSessionForActiveService(args,
58                         sourceFlags, showCallback, activityToken);
59             }
60         } catch (RemoteException e) {
61             Log.w(TAG, "Failed to call showSessionForActiveService", e);
62         }
63         return false;
64     }
65 
66     /**
67      * Checks the availability of a set of voice actions for the current active voice service.
68      *
69      * @param voiceActions A set of supported voice actions to be checked.
70      * @param callback     The callback which will deliver a set of supported voice actions. If
71      *                     no voice actions are supported for the given voice action set, then null
72      *                     or empty set is provided.
73      */
getActiveServiceSupportedActions(@onNull Set<String> voiceActions, @NonNull IVoiceActionCheckCallback callback)74     public void getActiveServiceSupportedActions(@NonNull Set<String> voiceActions,
75             @NonNull IVoiceActionCheckCallback callback) {
76         try {
77             if (mVoiceInteractionManagerService != null) {
78                 mVoiceInteractionManagerService
79                         .getActiveServiceSupportedActions(new ArrayList<>(voiceActions), callback);
80             }
81         } catch (RemoteException e) {
82             Log.w(TAG, "Failed to call activeServiceSupportedActions", e);
83             try {
84                 callback.onComplete(null);
85             } catch (RemoteException re) {
86             }
87         }
88     }
89 
launchVoiceAssistFromKeyguard()90     public void launchVoiceAssistFromKeyguard() {
91         try {
92             if (mVoiceInteractionManagerService != null) {
93                 mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard();
94             }
95         } catch (RemoteException e) {
96             Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e);
97         }
98     }
99 
activeServiceSupportsAssistGesture()100     public boolean activeServiceSupportsAssistGesture() {
101         try {
102             return mVoiceInteractionManagerService != null
103                     && mVoiceInteractionManagerService.activeServiceSupportsAssist();
104         } catch (RemoteException e) {
105             Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e);
106             return false;
107         }
108     }
109 
activeServiceSupportsLaunchFromKeyguard()110     public boolean activeServiceSupportsLaunchFromKeyguard() {
111         try {
112             return mVoiceInteractionManagerService != null
113                     && mVoiceInteractionManagerService.activeServiceSupportsLaunchFromKeyguard();
114         } catch (RemoteException e) {
115             Log.w(TAG, "Failed to call activeServiceSupportsLaunchFromKeyguard", e);
116             return false;
117         }
118     }
119 
getActiveServiceComponentName()120     public ComponentName getActiveServiceComponentName() {
121         try {
122             if (mVoiceInteractionManagerService != null) {
123                 return mVoiceInteractionManagerService.getActiveServiceComponentName();
124             } else {
125                 return null;
126             }
127         } catch (RemoteException e) {
128             Log.w(TAG, "Failed to call getActiveServiceComponentName", e);
129             return null;
130         }
131     }
132 
isSessionRunning()133     public boolean isSessionRunning() {
134         try {
135             return mVoiceInteractionManagerService != null
136                     && mVoiceInteractionManagerService.isSessionRunning();
137         } catch (RemoteException e) {
138             Log.w(TAG, "Failed to call isSessionRunning", e);
139             return false;
140         }
141     }
142 
hideCurrentSession()143     public void hideCurrentSession() {
144         try {
145             if (mVoiceInteractionManagerService != null) {
146                 mVoiceInteractionManagerService.hideCurrentSession();
147             }
148         } catch (RemoteException e) {
149             Log.w(TAG, "Failed to call hideCurrentSession", e);
150         }
151     }
152 
onLockscreenShown()153     public void onLockscreenShown() {
154         try {
155             if (mVoiceInteractionManagerService != null) {
156                 mVoiceInteractionManagerService.onLockscreenShown();
157             }
158         } catch (RemoteException e) {
159             Log.w(TAG, "Failed to call onLockscreenShown", e);
160         }
161     }
162 
registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener)163     public void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener) {
164         try {
165             if (mVoiceInteractionManagerService != null) {
166                 mVoiceInteractionManagerService.registerVoiceInteractionSessionListener(listener);
167             }
168         } catch (RemoteException e) {
169             Log.w(TAG, "Failed to register voice interaction listener", e);
170         }
171     }
172 
173     @UnsupportedAppUsage
getAssistComponentForUser(int userId)174     public ComponentName getAssistComponentForUser(int userId) {
175         final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
176                 Settings.Secure.ASSISTANT, userId);
177         if (setting != null) {
178             return ComponentName.unflattenFromString(setting);
179         } else {
180             return null;
181         }
182     }
183 
isPreinstalledAssistant(Context context, ComponentName assistant)184     public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) {
185         if (assistant == null) {
186             return false;
187         }
188         ApplicationInfo applicationInfo;
189         try {
190             applicationInfo = context.getPackageManager().getApplicationInfo(
191                     assistant.getPackageName(), 0);
192         } catch (PackageManager.NameNotFoundException e) {
193             return false;
194         }
195         return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp();
196     }
197 
isDisclosureEnabled(Context context)198     public static boolean isDisclosureEnabled(Context context) {
199         return Settings.Secure.getInt(context.getContentResolver(),
200                 Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0;
201     }
202 
203     /**
204      * @return if the disclosure animation should trigger for the given assistant.
205      *
206      * Third-party assistants will always need to disclose, while the user can configure this for
207      * pre-installed assistants.
208      */
shouldDisclose(Context context, ComponentName assistant)209     public static boolean shouldDisclose(Context context, ComponentName assistant) {
210         if (!allowDisablingAssistDisclosure(context)) {
211             return true;
212         }
213 
214         return isDisclosureEnabled(context) || !isPreinstalledAssistant(context, assistant);
215     }
216 
allowDisablingAssistDisclosure(Context context)217     public static boolean allowDisablingAssistDisclosure(Context context) {
218         return context.getResources().getBoolean(
219                 com.android.internal.R.bool.config_allowDisablingAssistDisclosure);
220     }
221 }
222