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 46 public AssistUtils(Context context) { 47 mContext = context; 48 mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface( 49 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); 50 } 51 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 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 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 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 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 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 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 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 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 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 160 Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) 161 .getAssistIntent(false); 162 PackageManager pm = mContext.getPackageManager(); 163 ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY, 164 userId); 165 if (info != null) { 166 return new ComponentName(info.activityInfo.applicationInfo.packageName, 167 info.activityInfo.name); 168 } 169 return null; 170 } 171 172 public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) { 173 if (assistant == null) { 174 return false; 175 } 176 ApplicationInfo applicationInfo; 177 try { 178 applicationInfo = context.getPackageManager().getApplicationInfo( 179 assistant.getPackageName(), 0); 180 } catch (PackageManager.NameNotFoundException e) { 181 return false; 182 } 183 return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp(); 184 } 185 186 private static boolean isDisclosureEnabled(Context context) { 187 return Settings.Secure.getInt(context.getContentResolver(), 188 Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0; 189 } 190 191 /** 192 * @return if the disclosure animation should trigger for the given assistant. 193 * 194 * Third-party assistants will always need to disclose, while the user can configure this for 195 * pre-installed assistants. 196 */ 197 public static boolean shouldDisclose(Context context, ComponentName assistant) { 198 if (!allowDisablingAssistDisclosure(context)) { 199 return true; 200 } 201 202 return isDisclosureEnabled(context) || !isPreinstalledAssistant(context, assistant); 203 } 204 205 public static boolean allowDisablingAssistDisclosure(Context context) { 206 return context.getResources().getBoolean( 207 com.android.internal.R.bool.config_allowDisablingAssistDisclosure); 208 } 209 } 210