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 com.android.internal.R; 20 21 import android.app.SearchManager; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.os.RemoteException; 31 import android.os.ServiceManager; 32 import android.provider.Settings; 33 import android.util.Log; 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 AssistUtils(Context context)46 public AssistUtils(Context context) { 47 mContext = context; 48 mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface( 49 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); 50 } 51 showSessionForActiveService(Bundle args, int sourceFlags, IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken)52 public boolean showSessionForActiveService(Bundle args, int sourceFlags, 53 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { 54 try { 55 if (mVoiceInteractionManagerService != null) { 56 return mVoiceInteractionManagerService.showSessionForActiveService(args, 57 sourceFlags, showCallback, activityToken); 58 } 59 } catch (RemoteException e) { 60 Log.w(TAG, "Failed to call showSessionForActiveService", e); 61 } 62 return false; 63 } 64 launchVoiceAssistFromKeyguard()65 public void launchVoiceAssistFromKeyguard() { 66 try { 67 if (mVoiceInteractionManagerService != null) { 68 mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard(); 69 } 70 } catch (RemoteException e) { 71 Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e); 72 } 73 } 74 activeServiceSupportsAssistGesture()75 public boolean activeServiceSupportsAssistGesture() { 76 try { 77 return mVoiceInteractionManagerService != null 78 && mVoiceInteractionManagerService.activeServiceSupportsAssist(); 79 } catch (RemoteException e) { 80 Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e); 81 return false; 82 } 83 } 84 activeServiceSupportsLaunchFromKeyguard()85 public boolean activeServiceSupportsLaunchFromKeyguard() { 86 try { 87 return mVoiceInteractionManagerService != null 88 && mVoiceInteractionManagerService.activeServiceSupportsLaunchFromKeyguard(); 89 } catch (RemoteException e) { 90 Log.w(TAG, "Failed to call activeServiceSupportsLaunchFromKeyguard", e); 91 return false; 92 } 93 } 94 getActiveServiceComponentName()95 public ComponentName getActiveServiceComponentName() { 96 try { 97 if (mVoiceInteractionManagerService != null) { 98 return mVoiceInteractionManagerService.getActiveServiceComponentName(); 99 } else { 100 return null; 101 } 102 } catch (RemoteException e) { 103 Log.w(TAG, "Failed to call getActiveServiceComponentName", e); 104 return null; 105 } 106 } 107 isSessionRunning()108 public boolean isSessionRunning() { 109 try { 110 return mVoiceInteractionManagerService != null 111 && mVoiceInteractionManagerService.isSessionRunning(); 112 } catch (RemoteException e) { 113 Log.w(TAG, "Failed to call isSessionRunning", e); 114 return false; 115 } 116 } 117 hideCurrentSession()118 public void hideCurrentSession() { 119 try { 120 if (mVoiceInteractionManagerService != null) { 121 mVoiceInteractionManagerService.hideCurrentSession(); 122 } 123 } catch (RemoteException e) { 124 Log.w(TAG, "Failed to call hideCurrentSession", e); 125 } 126 } 127 onLockscreenShown()128 public void onLockscreenShown() { 129 try { 130 if (mVoiceInteractionManagerService != null) { 131 mVoiceInteractionManagerService.onLockscreenShown(); 132 } 133 } catch (RemoteException e) { 134 Log.w(TAG, "Failed to call onLockscreenShown", e); 135 } 136 } 137 registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener)138 public void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener) { 139 try { 140 if (mVoiceInteractionManagerService != null) { 141 mVoiceInteractionManagerService.registerVoiceInteractionSessionListener(listener); 142 } 143 } catch (RemoteException e) { 144 Log.w(TAG, "Failed to register voice interaction listener", e); 145 } 146 } 147 getAssistComponentForUser(int userId)148 public ComponentName getAssistComponentForUser(int userId) { 149 final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), 150 Settings.Secure.ASSISTANT, userId); 151 if (setting != null) { 152 return ComponentName.unflattenFromString(setting); 153 } 154 155 // Fallback to keep backward compatible behavior when there is no user setting. 156 if (activeServiceSupportsAssistGesture()) { 157 return getActiveServiceComponentName(); 158 } 159 final SearchManager searchManager = 160 (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); 161 if (searchManager == null) { 162 return null; 163 } 164 final Intent intent = searchManager.getAssistIntent(false); 165 PackageManager pm = mContext.getPackageManager(); 166 ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY, 167 userId); 168 if (info != null) { 169 return new ComponentName(info.activityInfo.applicationInfo.packageName, 170 info.activityInfo.name); 171 } 172 return null; 173 } 174 isPreinstalledAssistant(Context context, ComponentName assistant)175 public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) { 176 if (assistant == null) { 177 return false; 178 } 179 ApplicationInfo applicationInfo; 180 try { 181 applicationInfo = context.getPackageManager().getApplicationInfo( 182 assistant.getPackageName(), 0); 183 } catch (PackageManager.NameNotFoundException e) { 184 return false; 185 } 186 return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp(); 187 } 188 isDisclosureEnabled(Context context)189 private static boolean isDisclosureEnabled(Context context) { 190 return Settings.Secure.getInt(context.getContentResolver(), 191 Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0; 192 } 193 194 /** 195 * @return if the disclosure animation should trigger for the given assistant. 196 * 197 * Third-party assistants will always need to disclose, while the user can configure this for 198 * pre-installed assistants. 199 */ shouldDisclose(Context context, ComponentName assistant)200 public static boolean shouldDisclose(Context context, ComponentName assistant) { 201 if (!allowDisablingAssistDisclosure(context)) { 202 return true; 203 } 204 205 return isDisclosureEnabled(context) || !isPreinstalledAssistant(context, assistant); 206 } 207 allowDisablingAssistDisclosure(Context context)208 public static boolean allowDisablingAssistDisclosure(Context context) { 209 return context.getResources().getBoolean( 210 com.android.internal.R.bool.config_allowDisablingAssistDisclosure); 211 } 212 } 213