blob: e1ffb0f179f847413b82491f87364e7bfa641042 [file] [log] [blame]
Dianne Hackborn91097de2014-04-04 18:02:06 -07001/*
2 * Copyright (C) 2014 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
17package com.android.server.voiceinteraction;
18
Dianne Hackborn18f0d352014-04-25 17:06:18 -070019import android.Manifest;
Philip P. Moltmann5d894502019-01-17 10:31:00 -080020import android.annotation.CallbackExecutor;
21import android.annotation.NonNull;
Sunny Goyald40c3452019-03-20 12:46:55 -070022import android.annotation.Nullable;
Dianne Hackborn91097de2014-04-04 18:02:06 -070023import android.app.ActivityManager;
Amith Yamasani0af6fa72016-01-17 15:36:19 -080024import android.app.ActivityManagerInternal;
Dianne Hackborna351ab92014-08-08 17:35:50 -070025import android.app.AppGlobals;
Philip P. Moltmann5d894502019-01-17 10:31:00 -080026import android.app.role.OnRoleHoldersChangedListener;
27import android.app.role.RoleManager;
Dianne Hackborn91097de2014-04-04 18:02:06 -070028import android.content.ComponentName;
29import android.content.ContentResolver;
30import android.content.Context;
31import android.content.Intent;
Philip P. Moltmann5d894502019-01-17 10:31:00 -080032import android.content.pm.ActivityInfo;
Dianne Hackborna351ab92014-08-08 17:35:50 -070033import android.content.pm.ApplicationInfo;
34import android.content.pm.IPackageManager;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070035import android.content.pm.PackageManager;
Svet Ganovadc1cf42015-06-15 16:36:24 -070036import android.content.pm.PackageManagerInternal;
Dianne Hackborna351ab92014-08-08 17:35:50 -070037import android.content.pm.ResolveInfo;
38import android.content.pm.ServiceInfo;
Dianne Hackbornc160fa42017-11-01 16:14:26 -070039import android.content.pm.ShortcutServiceInternal;
Cedric Hoc663d992015-04-23 15:16:47 -070040import android.content.res.Resources;
Dianne Hackborn91097de2014-04-04 18:02:06 -070041import android.database.ContentObserver;
Sandeep Siddhartha05589722014-07-17 16:21:54 -070042import android.hardware.soundtrigger.IRecognitionStatusCallback;
43import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
44import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
45import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
Dianne Hackborn91097de2014-04-04 18:02:06 -070046import android.os.Binder;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070047import android.os.Bundle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070048import android.os.Handler;
Dianne Hackborn18f0d352014-04-25 17:06:18 -070049import android.os.IBinder;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070050import android.os.Parcel;
Sunny Goyald40c3452019-03-20 12:46:55 -070051import android.os.RemoteCallback;
Annie Chinecb9f3e2016-06-27 16:01:52 -070052import android.os.RemoteCallbackList;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070053import android.os.RemoteException;
Dianne Hackborn91097de2014-04-04 18:02:06 -070054import android.os.UserHandle;
Dianne Hackbornc160fa42017-11-01 16:14:26 -070055import android.os.UserManager;
Dianne Hackborn91097de2014-04-04 18:02:06 -070056import android.provider.Settings;
57import android.service.voice.IVoiceInteractionService;
58import android.service.voice.IVoiceInteractionSession;
Amith Yamasani0af6fa72016-01-17 15:36:19 -080059import android.service.voice.VoiceInteractionManagerInternal;
Dianne Hackborna351ab92014-08-08 17:35:50 -070060import android.service.voice.VoiceInteractionService;
61import android.service.voice.VoiceInteractionServiceInfo;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -070062import android.service.voice.VoiceInteractionSession;
Dianne Hackborna351ab92014-08-08 17:35:50 -070063import android.speech.RecognitionService;
Dianne Hackborna351ab92014-08-08 17:35:50 -070064import android.text.TextUtils;
Dianne Hackbornc160fa42017-11-01 16:14:26 -070065import android.util.ArraySet;
Jorim Jaggib835dd72015-06-08 12:28:42 -070066import android.util.Log;
Dianne Hackborn91097de2014-04-04 18:02:06 -070067import android.util.Slog;
Sandeepd7018202014-07-10 15:15:39 -070068
Matt Casey4cff16f2019-01-14 14:56:06 -050069import com.android.internal.app.IVoiceActionCheckCallback;
Dianne Hackborn91097de2014-04-04 18:02:06 -070070import com.android.internal.app.IVoiceInteractionManagerService;
Matt Casey4cff16f2019-01-14 14:56:06 -050071import com.android.internal.app.IVoiceInteractionSessionListener;
Jorim Jaggi225d3b52015-04-01 11:18:57 -070072import com.android.internal.app.IVoiceInteractionSessionShowCallback;
Dianne Hackborn91097de2014-04-04 18:02:06 -070073import com.android.internal.app.IVoiceInteractor;
74import com.android.internal.content.PackageMonitor;
75import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060076import com.android.internal.util.DumpUtils;
Dianne Hackbornc160fa42017-11-01 16:14:26 -070077import com.android.internal.util.Preconditions;
Fyodor Kupolovab781c22017-12-19 16:44:26 -080078import com.android.server.FgThread;
Svet Ganovadc1cf42015-06-15 16:36:24 -070079import com.android.server.LocalServices;
Dianne Hackborn91097de2014-04-04 18:02:06 -070080import com.android.server.SystemService;
81import com.android.server.UiThread;
Annie Chinecb9f3e2016-06-27 16:01:52 -070082import com.android.server.soundtrigger.SoundTriggerInternal;
Matt Casey4cff16f2019-01-14 14:56:06 -050083import com.android.server.wm.ActivityTaskManagerInternal;
Dianne Hackborn91097de2014-04-04 18:02:06 -070084
85import java.io.FileDescriptor;
86import java.io.PrintWriter;
Dianne Hackborna351ab92014-08-08 17:35:50 -070087import java.util.List;
Philip P. Moltmann5d894502019-01-17 10:31:00 -080088import java.util.concurrent.Executor;
Dianne Hackborn91097de2014-04-04 18:02:06 -070089
90/**
91 * SystemService that publishes an IVoiceInteractionManagerService.
92 */
93public class VoiceInteractionManagerService extends SystemService {
Dianne Hackborn91097de2014-04-04 18:02:06 -070094 static final String TAG = "VoiceInteractionManagerService";
Joe Onorato3973b1a2016-02-01 17:45:31 -080095 static final boolean DEBUG = false;
Dianne Hackborn91097de2014-04-04 18:02:06 -070096
97 final Context mContext;
98 final ContentResolver mResolver;
Sandeep Siddhartha2883ba62014-07-16 21:02:08 -070099 final DatabaseHelper mDbHelper;
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800100 final ActivityManagerInternal mAmInternal;
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700101 final ActivityTaskManagerInternal mAtmInternal;
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700102 final UserManager mUserManager;
103 final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
104 ShortcutServiceInternal mShortcutServiceInternal;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800105 SoundTriggerInternal mSoundTriggerInternal;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700106
Annie Chind953ab62016-07-07 11:57:33 -0700107 private final RemoteCallbackList<IVoiceInteractionSessionListener>
108 mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
109
Dianne Hackborn91097de2014-04-04 18:02:06 -0700110 public VoiceInteractionManagerService(Context context) {
111 super(context);
112 mContext = context;
113 mResolver = context.getContentResolver();
Sandeep Siddhartha2883ba62014-07-16 21:02:08 -0700114 mDbHelper = new DatabaseHelper(context);
Cedric Hoc663d992015-04-23 15:16:47 -0700115 mServiceStub = new VoiceInteractionManagerServiceStub();
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700116 mAmInternal = Preconditions.checkNotNull(
117 LocalServices.getService(ActivityManagerInternal.class));
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700118 mAtmInternal = Preconditions.checkNotNull(
119 LocalServices.getService(ActivityTaskManagerInternal.class));
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700120 mUserManager = Preconditions.checkNotNull(
121 context.getSystemService(UserManager.class));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700122
123 PackageManagerInternal packageManagerInternal = LocalServices.getService(
124 PackageManagerInternal.class);
125 packageManagerInternal.setVoiceInteractionPackagesProvider(
126 new PackageManagerInternal.PackagesProvider() {
127 @Override
128 public String[] getPackages(int userId) {
129 mServiceStub.initForUser(userId);
130 ComponentName interactor = mServiceStub.getCurInteractor(userId);
131 if (interactor != null) {
132 return new String[] {interactor.getPackageName()};
133 }
134 return null;
135 }
136 });
Dianne Hackborn91097de2014-04-04 18:02:06 -0700137 }
138
139 @Override
140 public void onStart() {
141 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800142 publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
Dianne Hackborn91097de2014-04-04 18:02:06 -0700143 }
144
145 @Override
146 public void onBootPhase(int phase) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800147 if (PHASE_SYSTEM_SERVICES_READY == phase) {
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700148 mShortcutServiceInternal = Preconditions.checkNotNull(
149 LocalServices.getService(ShortcutServiceInternal.class));
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800150 mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
151 } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700152 mServiceStub.systemRunning(isSafeMode());
153 }
154 }
155
156 @Override
Dianne Hackborna351ab92014-08-08 17:35:50 -0700157 public void onStartUser(int userHandle) {
158 mServiceStub.initForUser(userHandle);
159 }
160
161 @Override
Amith Yamasani37f9de92016-04-19 17:04:28 -0700162 public void onUnlockUser(int userHandle) {
163 mServiceStub.initForUser(userHandle);
164 mServiceStub.switchImplementationIfNeeded(false);
165 }
166
167 @Override
Dianne Hackborn91097de2014-04-04 18:02:06 -0700168 public void onSwitchUser(int userHandle) {
169 mServiceStub.switchUser(userHandle);
170 }
171
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800172 class LocalService extends VoiceInteractionManagerInternal {
173 @Override
174 public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
175 if (DEBUG) {
176 Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity);
177 }
178 VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction(
179 callingActivity, options);
180 }
181
182 @Override
183 public boolean supportsLocalVoiceInteraction() {
184 return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
185 }
186
187 @Override
188 public void stopLocalVoiceInteraction(IBinder callingActivity) {
189 if (DEBUG) {
190 Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity);
191 }
192 VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction(
193 callingActivity);
194 }
195 }
196
Dianne Hackborn91097de2014-04-04 18:02:06 -0700197 // implementation entry point and binder service
Cedric Hoc663d992015-04-23 15:16:47 -0700198 private final VoiceInteractionManagerServiceStub mServiceStub;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700199
200 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
201
202 VoiceInteractionManagerServiceImpl mImpl;
203
204 private boolean mSafeMode;
205 private int mCurUser;
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700206 private boolean mCurUserUnlocked;
Cedric Hoc663d992015-04-23 15:16:47 -0700207 private final boolean mEnableService;
208
209 VoiceInteractionManagerServiceStub() {
Dianne Hackborn31cb01d2017-08-30 16:21:28 -0700210 mEnableService = shouldEnableService(mContext);
Philip P. Moltmann5d894502019-01-17 10:31:00 -0800211 new RoleObserver(mContext.getMainExecutor());
Cedric Hoc663d992015-04-23 15:16:47 -0700212 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700213
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800214 // TODO: VI Make sure the caller is the current user or profile
215 void startLocalVoiceInteraction(final IBinder token, Bundle options) {
216 if (mImpl == null) return;
217
218 final long caller = Binder.clearCallingIdentity();
219 try {
220 mImpl.showSessionLocked(options,
221 VoiceInteractionSession.SHOW_SOURCE_ACTIVITY,
222 new IVoiceInteractionSessionShowCallback.Stub() {
223 @Override
224 public void onFailed() {
225 }
226
227 @Override
228 public void onShown() {
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700229 mAtmInternal.onLocalVoiceInteractionStarted(token,
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800230 mImpl.mActiveSession.mSession,
231 mImpl.mActiveSession.mInteractor);
232 }
233 },
234 token);
235 } finally {
236 Binder.restoreCallingIdentity(caller);
237 }
238 }
239
240 public void stopLocalVoiceInteraction(IBinder callingActivity) {
241 if (mImpl == null) return;
242
243 final long caller = Binder.clearCallingIdentity();
244 try {
245 mImpl.finishLocked(callingActivity, true);
246 } finally {
247 Binder.restoreCallingIdentity(caller);
248 }
249 }
250
251 public boolean supportsLocalVoiceInteraction() {
252 if (mImpl == null) return false;
253
254 return mImpl.supportsLocalVoiceInteraction();
255 }
256
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700257 @Override
258 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
259 throws RemoteException {
260 try {
261 return super.onTransact(code, data, reply, flags);
262 } catch (RuntimeException e) {
263 // The activity manager only throws security exceptions, so let's
264 // log all others.
265 if (!(e instanceof SecurityException)) {
266 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
267 }
268 throw e;
269 }
270 }
271
Dianne Hackborna351ab92014-08-08 17:35:50 -0700272 public void initForUser(int userHandle) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800273 if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700274 String curInteractorStr = Settings.Secure.getStringForUser(
275 mContext.getContentResolver(),
276 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700277 ComponentName curRecognizer = getCurRecognizer(userHandle);
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700278 VoiceInteractionServiceInfo curInteractorInfo = null;
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800279 if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
280 + " curRecognizer=" + curRecognizer);
Cedric Hoc663d992015-04-23 15:16:47 -0700281 if (curInteractorStr == null && curRecognizer != null && mEnableService) {
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700282 // If there is no interactor setting, that means we are upgrading
283 // from an older platform version. If the current recognizer is not
284 // set or matches the preferred recognizer, then we want to upgrade
285 // the user to have the default voice interaction service enabled.
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800286 // Note that we don't do this for low-RAM devices, since we aren't
287 // supporting voice interaction services there.
Cedric Ho80cf2212015-05-19 15:44:31 -0700288 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700289 if (curInteractorInfo != null) {
290 // Looks good! We'll apply this one. To make it happen, we clear the
291 // recognizer so that we don't think we have anything set and will
292 // re-apply the settings.
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800293 if (DEBUG) Slog.d(TAG, "No set interactor, found avail: "
294 + curInteractorInfo.getServiceInfo().name);
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700295 curRecognizer = null;
296 }
297 }
298
Cedric Ho80cf2212015-05-19 15:44:31 -0700299 // If forceInteractorPackage exists, try to apply the interactor from this package if
300 // possible and ignore the regular interactor setting.
301 String forceInteractorPackage =
302 getForceVoiceInteractionServicePackage(mContext.getResources());
303 if (forceInteractorPackage != null) {
304 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
305 if (curInteractorInfo != null) {
306 // We'll apply this one. Clear the recognizer and re-apply the settings.
307 curRecognizer = null;
308 }
309 }
310
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800311 // If we are on a svelte device, make sure an interactor is not currently
312 // enabled; if it is, turn it off.
Cedric Hoc663d992015-04-23 15:16:47 -0700313 if (!mEnableService && curInteractorStr != null) {
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800314 if (!TextUtils.isEmpty(curInteractorStr)) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800315 if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor");
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800316 setCurInteractor(null, userHandle);
317 curInteractorStr = "";
318 }
319 }
320
Dianne Hackborna351ab92014-08-08 17:35:50 -0700321 if (curRecognizer != null) {
322 // If we already have at least a recognizer, then we probably want to
323 // leave things as they are... unless something has disappeared.
324 IPackageManager pm = AppGlobals.getPackageManager();
325 ServiceInfo interactorInfo = null;
326 ServiceInfo recognizerInfo = null;
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700327 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
328 ? ComponentName.unflattenFromString(curInteractorStr) : null;
Dianne Hackborna351ab92014-08-08 17:35:50 -0700329 try {
Sudheer Shanka9260d562017-04-10 15:32:52 -0700330 recognizerInfo = pm.getServiceInfo(curRecognizer,
331 PackageManager.MATCH_DIRECT_BOOT_AWARE
332 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700333 if (curInteractor != null) {
Sudheer Shanka9260d562017-04-10 15:32:52 -0700334 interactorInfo = pm.getServiceInfo(curInteractor,
335 PackageManager.MATCH_DIRECT_BOOT_AWARE
336 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700337 }
338 } catch (RemoteException e) {
339 }
340 // If the apps for the currently set components still exist, then all is okay.
341 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800342 if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!");
Dianne Hackborna351ab92014-08-08 17:35:50 -0700343 return;
344 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800345 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor ("
346 + interactorInfo + ")");
Dianne Hackborna351ab92014-08-08 17:35:50 -0700347 }
348
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800349 // Initializing settings, look for an interactor first (but only on non-svelte).
Cedric Hoc663d992015-04-23 15:16:47 -0700350 if (curInteractorInfo == null && mEnableService) {
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700351 curInteractorInfo = findAvailInteractor(userHandle, null);
352 }
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800353
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700354 if (curInteractorInfo != null) {
355 // Eventually it will be an error to not specify this.
356 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
357 curInteractorInfo.getServiceInfo().name), userHandle);
358 if (curInteractorInfo.getRecognitionService() != null) {
359 setCurRecognizer(
360 new ComponentName(curInteractorInfo.getServiceInfo().packageName,
361 curInteractorInfo.getRecognitionService()), userHandle);
362 return;
Dianne Hackborna351ab92014-08-08 17:35:50 -0700363 }
364 }
365
366 // No voice interactor, we'll just set up a simple recognizer.
Dianne Hackborn3d7ab612018-12-17 10:53:53 -0800367 initSimpleRecognizer(curInteractorInfo, userHandle);
368 }
369
370 public void initSimpleRecognizer(VoiceInteractionServiceInfo curInteractorInfo,
371 int userHandle) {
372 ComponentName curRecognizer = findAvailRecognizer(null, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700373 if (curRecognizer != null) {
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700374 if (curInteractorInfo == null) {
375 setCurInteractor(null, userHandle);
376 }
Dianne Hackborna351ab92014-08-08 17:35:50 -0700377 setCurRecognizer(curRecognizer, userHandle);
378 }
379 }
380
Dianne Hackborn31cb01d2017-08-30 16:21:28 -0700381 private boolean shouldEnableService(Context context) {
Robin Leeba3af562018-11-13 18:48:19 +0100382 // VoiceInteractionService should not be enabled on devices that have not declared the
383 // recognition feature (including low-ram devices where notLowRam="true" takes effect),
384 // unless the device's configuration has explicitly set the config flag for a fixed
Dianne Hackborn31cb01d2017-08-30 16:21:28 -0700385 // voice interaction service.
Robin Leeba3af562018-11-13 18:48:19 +0100386 if (getForceVoiceInteractionServicePackage(context.getResources()) != null) {
387 return true;
388 }
389 return context.getPackageManager()
390 .hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS);
Cedric Ho80cf2212015-05-19 15:44:31 -0700391 }
392
393 private String getForceVoiceInteractionServicePackage(Resources res) {
394 String interactorPackage =
395 res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
396 return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
Cedric Hoc663d992015-04-23 15:16:47 -0700397 }
398
Dianne Hackborn91097de2014-04-04 18:02:06 -0700399 public void systemRunning(boolean safeMode) {
400 mSafeMode = safeMode;
401
402 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
403 UserHandle.ALL, true);
404 new SettingsObserver(UiThread.getHandler());
405
406 synchronized (this) {
407 mCurUser = ActivityManager.getCurrentUser();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700408 switchImplementationIfNeededLocked(false);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700409 }
410 }
411
412 public void switchUser(int userHandle) {
Fyodor Kupolovab781c22017-12-19 16:44:26 -0800413 FgThread.getHandler().post(() -> {
414 synchronized (this) {
415 mCurUser = userHandle;
416 mCurUserUnlocked = false;
417 switchImplementationIfNeededLocked(false);
418 }
419 });
Dianne Hackborn91097de2014-04-04 18:02:06 -0700420 }
421
Amith Yamasani37f9de92016-04-19 17:04:28 -0700422 void switchImplementationIfNeeded(boolean force) {
423 synchronized (this) {
424 switchImplementationIfNeededLocked(force);
425 }
426 }
427
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700428 void switchImplementationIfNeededLocked(boolean force) {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700429 if (!mSafeMode) {
430 String curService = Settings.Secure.getStringForUser(
431 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
432 ComponentName serviceComponent = null;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800433 ServiceInfo serviceInfo = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700434 if (curService != null && !curService.isEmpty()) {
435 try {
436 serviceComponent = ComponentName.unflattenFromString(curService);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800437 serviceInfo = AppGlobals.getPackageManager()
438 .getServiceInfo(serviceComponent, 0, mCurUser);
439 } catch (RuntimeException | RemoteException e) {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700440 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
441 serviceComponent = null;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800442 serviceInfo = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700443 }
444 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800445
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700446 final boolean hasComponent = serviceComponent != null && serviceInfo != null;
447
448 if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
449 if (hasComponent) {
450 mShortcutServiceInternal.setShortcutHostPackage(TAG,
451 serviceComponent.getPackageName(), mCurUser);
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700452 mAtmInternal.setAllowAppSwitches(TAG,
Dianne Hackborn08bd3ea2017-11-22 13:59:17 -0800453 serviceInfo.applicationInfo.uid, mCurUser);
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700454 } else {
455 mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700456 mAtmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700457 }
458 }
459
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700460 if (force || mImpl == null || mImpl.mUser != mCurUser
Dianne Hackborn91097de2014-04-04 18:02:06 -0700461 || !mImpl.mComponent.equals(serviceComponent)) {
Chris Thorntonf967da92016-05-02 19:22:57 -0700462 unloadAllKeyphraseModels();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700463 if (mImpl != null) {
464 mImpl.shutdownLocked();
465 }
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700466 if (hasComponent) {
Winson Chungbccd4b52017-12-13 11:08:39 -0800467 setImplLocked(new VoiceInteractionManagerServiceImpl(mContext,
468 UiThread.getHandler(), this, mCurUser, serviceComponent));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700469 mImpl.startLocked();
470 } else {
Winson Chungbccd4b52017-12-13 11:08:39 -0800471 setImplLocked(null);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700472 }
473 }
474 }
475 }
476
Cedric Ho80cf2212015-05-19 15:44:31 -0700477 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
Dianne Hackborna351ab92014-08-08 17:35:50 -0700478 List<ResolveInfo> available =
479 mContext.getPackageManager().queryIntentServicesAsUser(
Svetoslav Ganovb625e192016-06-02 15:25:12 -0700480 new Intent(VoiceInteractionService.SERVICE_INTERFACE),
481 PackageManager.MATCH_DIRECT_BOOT_AWARE
482 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
483 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700484 int numAvailable = available.size();
485
486 if (numAvailable == 0) {
487 Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
488 return null;
489 } else {
490 // Find first system package. We never want to allow third party services to
491 // be automatically selected, because those require approval of the user.
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700492 VoiceInteractionServiceInfo foundInfo = null;
Dianne Hackborna351ab92014-08-08 17:35:50 -0700493 for (int i=0; i<numAvailable; i++) {
494 ServiceInfo cur = available.get(i).serviceInfo;
495 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700496 ComponentName comp = new ComponentName(cur.packageName, cur.name);
497 try {
498 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
499 mContext.getPackageManager(), comp, userHandle);
500 if (info.getParseError() == null) {
Cedric Ho80cf2212015-05-19 15:44:31 -0700501 if (packageName == null || info.getServiceInfo().packageName.equals(
502 packageName)) {
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700503 if (foundInfo == null) {
504 foundInfo = info;
505 } else {
506 Slog.w(TAG, "More than one voice interaction service, "
507 + "picking first "
508 + new ComponentName(
509 foundInfo.getServiceInfo().packageName,
510 foundInfo.getServiceInfo().name)
511 + " over "
512 + new ComponentName(cur.packageName, cur.name));
513 }
514 }
515 } else {
516 Slog.w(TAG, "Bad interaction service " + comp + ": "
517 + info.getParseError());
518 }
519 } catch (PackageManager.NameNotFoundException e) {
520 Slog.w(TAG, "Failure looking up interaction service " + comp);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700521 }
522 }
523 }
524
Dianne Hackborn16ec0802014-08-15 18:32:33 -0700525 return foundInfo;
Dianne Hackborna351ab92014-08-08 17:35:50 -0700526 }
527 }
528
529 ComponentName getCurInteractor(int userHandle) {
530 String curInteractor = Settings.Secure.getStringForUser(
531 mContext.getContentResolver(),
532 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
533 if (TextUtils.isEmpty(curInteractor)) {
534 return null;
535 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800536 if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
Dianne Hackborna351ab92014-08-08 17:35:50 -0700537 + " user=" + userHandle);
538 return ComponentName.unflattenFromString(curInteractor);
539 }
540
541 void setCurInteractor(ComponentName comp, int userHandle) {
542 Settings.Secure.putStringForUser(mContext.getContentResolver(),
543 Settings.Secure.VOICE_INTERACTION_SERVICE,
544 comp != null ? comp.flattenToShortString() : "", userHandle);
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800545 if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp
Dianne Hackborna351ab92014-08-08 17:35:50 -0700546 + " user=" + userHandle);
547 }
548
549 ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
550 List<ResolveInfo> available =
551 mContext.getPackageManager().queryIntentServicesAsUser(
Sudheer Shanka9260d562017-04-10 15:32:52 -0700552 new Intent(RecognitionService.SERVICE_INTERFACE),
553 PackageManager.MATCH_DIRECT_BOOT_AWARE
554 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -0700555 int numAvailable = available.size();
556
557 if (numAvailable == 0) {
558 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
559 return null;
560 } else {
561 if (prefPackage != null) {
562 for (int i=0; i<numAvailable; i++) {
563 ServiceInfo serviceInfo = available.get(i).serviceInfo;
564 if (prefPackage.equals(serviceInfo.packageName)) {
565 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
566 }
567 }
568 }
569 if (numAvailable > 1) {
570 Slog.w(TAG, "more than one voice recognition service found, picking first");
571 }
572
573 ServiceInfo serviceInfo = available.get(0).serviceInfo;
574 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
575 }
576 }
577
578 ComponentName getCurRecognizer(int userHandle) {
579 String curRecognizer = Settings.Secure.getStringForUser(
580 mContext.getContentResolver(),
581 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
582 if (TextUtils.isEmpty(curRecognizer)) {
583 return null;
584 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800585 if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
Dianne Hackborna351ab92014-08-08 17:35:50 -0700586 + " user=" + userHandle);
587 return ComponentName.unflattenFromString(curRecognizer);
588 }
589
590 void setCurRecognizer(ComponentName comp, int userHandle) {
591 Settings.Secure.putStringForUser(mContext.getContentResolver(),
592 Settings.Secure.VOICE_RECOGNITION_SERVICE,
593 comp != null ? comp.flattenToShortString() : "", userHandle);
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800594 if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
Dianne Hackborna351ab92014-08-08 17:35:50 -0700595 + " user=" + userHandle);
596 }
597
Dianne Hackborne9563652016-08-18 17:33:41 -0700598 ComponentName getCurAssistant(int userHandle) {
599 String curAssistant = Settings.Secure.getStringForUser(
600 mContext.getContentResolver(),
601 Settings.Secure.ASSISTANT, userHandle);
602 if (TextUtils.isEmpty(curAssistant)) {
603 return null;
604 }
605 if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
606 + " user=" + userHandle);
607 return ComponentName.unflattenFromString(curAssistant);
608 }
609
Jorim Jaggicc3a46a2015-06-25 15:55:43 -0700610 void resetCurAssistant(int userHandle) {
611 Settings.Secure.putStringForUser(mContext.getContentResolver(),
612 Settings.Secure.ASSISTANT, null, userHandle);
613 }
614
Dianne Hackborn91097de2014-04-04 18:02:06 -0700615 @Override
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800616 public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700617 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -0500618 enforceIsCurrentVoiceInteractionService(service);
619
Dianne Hackborn91097de2014-04-04 18:02:06 -0700620 final long caller = Binder.clearCallingIdentity();
621 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700622 mImpl.showSessionLocked(args, flags, null, null);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700623 } finally {
624 Binder.restoreCallingIdentity(caller);
625 }
626 }
627 }
628
629 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700630 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700631 IVoiceInteractor interactor) {
632 synchronized (this) {
633 if (mImpl == null) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700634 throw new SecurityException(
635 "deliverNewSession without running voice interaction service");
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700636 }
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700637 final long caller = Binder.clearCallingIdentity();
638 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700639 return mImpl.deliverNewSessionLocked(token, session, interactor);
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700640 } finally {
641 Binder.restoreCallingIdentity(caller);
642 }
643 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700644 }
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700645
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700646 @Override
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800647 public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
648 synchronized (this) {
649 if (mImpl == null) {
650 Slog.w(TAG, "showSessionFromSession without running voice interaction service");
651 return false;
652 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800653 final long caller = Binder.clearCallingIdentity();
654 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700655 return mImpl.showSessionLocked(sessionArgs, flags, null, null);
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800656 } finally {
657 Binder.restoreCallingIdentity(caller);
658 }
659 }
660 }
661
662 @Override
663 public boolean hideSessionFromSession(IBinder token) {
664 synchronized (this) {
665 if (mImpl == null) {
666 Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
667 return false;
668 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800669 final long caller = Binder.clearCallingIdentity();
670 try {
Jorim Jaggib835dd72015-06-08 12:28:42 -0700671 return mImpl.hideSessionLocked();
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800672 } finally {
673 Binder.restoreCallingIdentity(caller);
674 }
675 }
676 }
677
678 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700679 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
680 synchronized (this) {
681 if (mImpl == null) {
682 Slog.w(TAG, "startVoiceActivity without running voice interaction service");
683 return ActivityManager.START_CANCELED;
684 }
685 final int callingPid = Binder.getCallingPid();
686 final int callingUid = Binder.getCallingUid();
687 final long caller = Binder.clearCallingIdentity();
688 try {
689 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
690 intent, resolvedType);
691 } finally {
692 Binder.restoreCallingIdentity(caller);
693 }
694 }
695 }
696
697 @Override
Winson Chung83471632016-12-13 11:02:12 -0800698 public int startAssistantActivity(IBinder token, Intent intent, String resolvedType) {
699 synchronized (this) {
700 if (mImpl == null) {
701 Slog.w(TAG, "startAssistantActivity without running voice interaction service");
702 return ActivityManager.START_CANCELED;
703 }
704 final int callingPid = Binder.getCallingPid();
705 final int callingUid = Binder.getCallingUid();
706 final long caller = Binder.clearCallingIdentity();
707 try {
708 return mImpl.startAssistantActivityLocked(callingPid, callingUid, token,
709 intent, resolvedType);
710 } finally {
711 Binder.restoreCallingIdentity(caller);
712 }
713 }
714 }
715
716 @Override
Svet Ganov3b6be082019-04-28 10:21:01 -0700717 public void requestDirectActions(@NonNull IBinder token, int taskId,
718 @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback,
719 @NonNull RemoteCallback resultCallback) {
Sunny Goyald40c3452019-03-20 12:46:55 -0700720 synchronized (this) {
721 if (mImpl == null) {
722 Slog.w(TAG, "requestDirectActions without running voice interaction service");
Svet Ganov3b6be082019-04-28 10:21:01 -0700723 resultCallback.sendResult(null);
Sunny Goyald40c3452019-03-20 12:46:55 -0700724 return;
725 }
726 final long caller = Binder.clearCallingIdentity();
727 try {
Svet Ganov3b6be082019-04-28 10:21:01 -0700728 mImpl.requestDirectActionsLocked(token, taskId, assistToken,
729 cancellationCallback, resultCallback);
Sunny Goyald40c3452019-03-20 12:46:55 -0700730 } finally {
731 Binder.restoreCallingIdentity(caller);
732 }
733 }
734 }
735
736 @Override
737 public void performDirectAction(@NonNull IBinder token, @NonNull String actionId,
738 @NonNull Bundle arguments, int taskId, IBinder assistToken,
739 @Nullable RemoteCallback cancellationCallback,
740 @NonNull RemoteCallback resultCallback) {
741 synchronized (this) {
742 if (mImpl == null) {
743 Slog.w(TAG, "performDirectAction without running voice interaction service");
744 resultCallback.sendResult(null);
745 return;
746 }
747 final long caller = Binder.clearCallingIdentity();
748 try {
749 mImpl.performDirectActionLocked(token, actionId, arguments, taskId,
750 assistToken, cancellationCallback, resultCallback);
751 } finally {
752 Binder.restoreCallingIdentity(caller);
753 }
754 }
755 }
756
757 @Override
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700758 public void setKeepAwake(IBinder token, boolean keepAwake) {
759 synchronized (this) {
760 if (mImpl == null) {
761 Slog.w(TAG, "setKeepAwake without running voice interaction service");
762 return;
763 }
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700764 final long caller = Binder.clearCallingIdentity();
765 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700766 mImpl.setKeepAwakeLocked(token, keepAwake);
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700767 } finally {
768 Binder.restoreCallingIdentity(caller);
769 }
770 }
771 }
772
773 @Override
Dianne Hackborn4e88bcd2015-07-01 13:41:03 -0700774 public void closeSystemDialogs(IBinder token) {
775 synchronized (this) {
776 if (mImpl == null) {
777 Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
778 return;
779 }
Dianne Hackborn4e88bcd2015-07-01 13:41:03 -0700780 final long caller = Binder.clearCallingIdentity();
781 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700782 mImpl.closeSystemDialogsLocked(token);
Dianne Hackborn4e88bcd2015-07-01 13:41:03 -0700783 } finally {
784 Binder.restoreCallingIdentity(caller);
785 }
786 }
787 }
788
789 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700790 public void finish(IBinder token) {
791 synchronized (this) {
792 if (mImpl == null) {
793 Slog.w(TAG, "finish without running voice interaction service");
794 return;
795 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700796 final long caller = Binder.clearCallingIdentity();
797 try {
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800798 mImpl.finishLocked(token, false);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700799 } finally {
800 Binder.restoreCallingIdentity(caller);
801 }
802 }
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700803 }
804
Dianne Hackborn1de11862015-07-15 14:20:51 -0700805 @Override
806 public void setDisabledShowContext(int flags) {
807 synchronized (this) {
808 if (mImpl == null) {
809 Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
810 return;
811 }
Dianne Hackborn1de11862015-07-15 14:20:51 -0700812 final int callingUid = Binder.getCallingUid();
813 final long caller = Binder.clearCallingIdentity();
814 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700815 mImpl.setDisabledShowContextLocked(callingUid, flags);
Dianne Hackborn1de11862015-07-15 14:20:51 -0700816 } finally {
817 Binder.restoreCallingIdentity(caller);
818 }
819 }
Dianne Hackborn1de11862015-07-15 14:20:51 -0700820 }
821
822 @Override
823 public int getDisabledShowContext() {
824 synchronized (this) {
825 if (mImpl == null) {
826 Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
827 return 0;
828 }
Dianne Hackborn1de11862015-07-15 14:20:51 -0700829 final int callingUid = Binder.getCallingUid();
830 final long caller = Binder.clearCallingIdentity();
831 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700832 return mImpl.getDisabledShowContextLocked(callingUid);
Dianne Hackborn1de11862015-07-15 14:20:51 -0700833 } finally {
834 Binder.restoreCallingIdentity(caller);
835 }
836 }
Dianne Hackborn17f69352015-07-17 18:04:14 -0700837 }
Dianne Hackborn1de11862015-07-15 14:20:51 -0700838
Dianne Hackborn17f69352015-07-17 18:04:14 -0700839 @Override
840 public int getUserDisabledShowContext() {
841 synchronized (this) {
842 if (mImpl == null) {
843 Slog.w(TAG,
844 "getUserDisabledShowContext without running voice interaction service");
845 return 0;
846 }
847 final int callingUid = Binder.getCallingUid();
848 final long caller = Binder.clearCallingIdentity();
849 try {
850 return mImpl.getUserDisabledShowContextLocked(callingUid);
851 } finally {
852 Binder.restoreCallingIdentity(caller);
853 }
854 }
Dianne Hackborn1de11862015-07-15 14:20:51 -0700855 }
856
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700857 //----------------- Model management APIs --------------------------------//
858
Dianne Hackborn18f0d352014-04-25 17:06:18 -0700859 @Override
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700860 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -0700861 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
Sandeepd7018202014-07-10 15:15:39 -0700862
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700863 if (bcp47Locale == null) {
864 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
865 }
866
867 final int callingUid = UserHandle.getCallingUserId();
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700868 final long caller = Binder.clearCallingIdentity();
869 try {
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700870 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700871 } finally {
872 Binder.restoreCallingIdentity(caller);
Sandeepd7018202014-07-10 15:15:39 -0700873 }
874 }
875
876 @Override
877 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -0700878 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
879 if (model == null) {
880 throw new IllegalArgumentException("Model must not be null");
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700881 }
Sandeep Siddharthaf8cf71d2014-07-16 22:53:19 -0700882
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700883 final long caller = Binder.clearCallingIdentity();
884 try {
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700885 if (mDbHelper.updateKeyphraseSoundModel(model)) {
886 synchronized (this) {
887 // Notify the voice interaction service of a change in sound models.
888 if (mImpl != null && mImpl.mService != null) {
889 mImpl.notifySoundModelsChangedLocked();
890 }
891 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800892 return SoundTriggerInternal.STATUS_OK;
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700893 } else {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800894 return SoundTriggerInternal.STATUS_ERROR;
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700895 }
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700896 } finally {
897 Binder.restoreCallingIdentity(caller);
898 }
899 }
900
901 @Override
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700902 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -0700903 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700904
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700905 if (bcp47Locale == null) {
906 throw new IllegalArgumentException(
907 "Illegal argument(s) in deleteKeyphraseSoundModel");
908 }
909
910 final int callingUid = UserHandle.getCallingUserId();
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700911 final long caller = Binder.clearCallingIdentity();
Sandeep Siddhartha256e1a62014-08-05 11:56:58 -0700912 boolean deleted = false;
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700913 try {
Arunesh Mishra2d1de782016-02-21 18:10:28 -0800914 int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
915 if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
916 Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
917 }
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700918 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800919 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
Sandeep Siddhartha256e1a62014-08-05 11:56:58 -0700920 } finally {
921 if (deleted) {
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700922 synchronized (this) {
Sandeep Siddhartha6daae962014-07-21 10:31:34 -0700923 // Notify the voice interaction service of a change in sound models.
924 if (mImpl != null && mImpl.mService != null) {
925 mImpl.notifySoundModelsChangedLocked();
Sandeep Siddharthaf8cf71d2014-07-16 22:53:19 -0700926 }
Chris Thorntonf967da92016-05-02 19:22:57 -0700927 mLoadedKeyphraseIds.remove(keyphraseId);
Sandeep Siddhartha2883ba62014-07-16 21:02:08 -0700928 }
Sandeepd7018202014-07-10 15:15:39 -0700929 }
Sandeep Siddharthaf63bc522014-07-22 09:49:49 -0700930 Binder.restoreCallingIdentity(caller);
Sandeepd7018202014-07-10 15:15:39 -0700931 }
932 }
933
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700934 //----------------- SoundTrigger APIs --------------------------------//
935 @Override
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700936 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
937 String bcp47Locale) {
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700938 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -0500939 enforceIsCurrentVoiceInteractionService(service);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700940 }
941
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700942 if (bcp47Locale == null) {
943 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
944 }
945
946 final int callingUid = UserHandle.getCallingUserId();
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700947 final long caller = Binder.clearCallingIdentity();
948 try {
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700949 KeyphraseSoundModel model =
950 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700951 return model != null;
952 } finally {
953 Binder.restoreCallingIdentity(caller);
954 }
955 }
956
957 @Override
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700958 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
959 // Allow the call if this is the current voice interaction service.
960 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -0500961 enforceIsCurrentVoiceInteractionService(service);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700962
963 final long caller = Binder.clearCallingIdentity();
964 try {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800965 return mSoundTriggerInternal.getModuleProperties();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700966 } finally {
967 Binder.restoreCallingIdentity(caller);
968 }
969 }
970 }
971
972 @Override
973 public int startRecognition(IVoiceInteractionService service, int keyphraseId,
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700974 String bcp47Locale, IRecognitionStatusCallback callback,
975 RecognitionConfig recognitionConfig) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700976 // Allow the call if this is the current voice interaction service.
977 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -0500978 enforceIsCurrentVoiceInteractionService(service);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700979
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700980 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700981 throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
982 }
983 }
984
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700985 int callingUid = UserHandle.getCallingUserId();
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700986 final long caller = Binder.clearCallingIdentity();
987 try {
Sandeep Siddhartha8cf8f712014-09-15 12:51:08 -0700988 KeyphraseSoundModel soundModel =
989 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700990 if (soundModel == null
991 || soundModel.uuid == null
992 || soundModel.keyphrases == null) {
993 Slog.w(TAG, "No matching sound model found in startRecognition");
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800994 return SoundTriggerInternal.STATUS_ERROR;
Sandeep Siddhartha452a6422014-07-25 10:49:34 -0700995 } else {
Chris Thorntonf967da92016-05-02 19:22:57 -0700996 // Regardless of the status of the start recognition, we need to make sure
997 // that we unload this model if needed later.
998 synchronized (this) {
999 mLoadedKeyphraseIds.add(keyphraseId);
1000 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001001 return mSoundTriggerInternal.startRecognition(
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001002 keyphraseId, soundModel, callback, recognitionConfig);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001003 }
Sandeep Siddhartha452a6422014-07-25 10:49:34 -07001004 } finally {
1005 Binder.restoreCallingIdentity(caller);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001006 }
1007 }
1008
1009 @Override
1010 public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
1011 IRecognitionStatusCallback callback) {
1012 // Allow the call if this is the current voice interaction service.
1013 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -05001014 enforceIsCurrentVoiceInteractionService(service);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -07001015 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001016
Sandeep Siddhartha452a6422014-07-25 10:49:34 -07001017 final long caller = Binder.clearCallingIdentity();
1018 try {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001019 return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
Sandeep Siddhartha452a6422014-07-25 10:49:34 -07001020 } finally {
1021 Binder.restoreCallingIdentity(caller);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001022 }
1023 }
1024
Chris Thorntonf967da92016-05-02 19:22:57 -07001025 private synchronized void unloadAllKeyphraseModels() {
Dianne Hackbornc160fa42017-11-01 16:14:26 -07001026 for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
Chris Thorntonf967da92016-05-02 19:22:57 -07001027 final long caller = Binder.clearCallingIdentity();
1028 try {
Dianne Hackbornc160fa42017-11-01 16:14:26 -07001029 int status = mSoundTriggerInternal.unloadKeyphraseModel(
1030 mLoadedKeyphraseIds.valueAt(i));
Chris Thorntonf967da92016-05-02 19:22:57 -07001031 if (status != SoundTriggerInternal.STATUS_OK) {
Dianne Hackbornc160fa42017-11-01 16:14:26 -07001032 Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
1033 + ":" + status);
Chris Thorntonf967da92016-05-02 19:22:57 -07001034 }
1035 } finally {
1036 Binder.restoreCallingIdentity(caller);
1037 }
1038 }
1039 mLoadedKeyphraseIds.clear();
1040 }
1041
Sandeepd7018202014-07-10 15:15:39 -07001042 @Override
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001043 public ComponentName getActiveServiceComponentName() {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001044 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001045 synchronized (this) {
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001046 return mImpl != null ? mImpl.mComponent : null;
1047 }
1048 }
1049
1050 @Override
Dianne Hackborn17f69352015-07-17 18:04:14 -07001051 public boolean showSessionForActiveService(Bundle args, int sourceFlags,
1052 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001053 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001054 synchronized (this) {
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001055 if (mImpl == null) {
1056 Slog.w(TAG, "showSessionForActiveService without running voice interaction"
1057 + "service");
Dianne Hackborn17f69352015-07-17 18:04:14 -07001058 return false;
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001059 }
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001060 final long caller = Binder.clearCallingIdentity();
1061 try {
Dianne Hackborn17f69352015-07-17 18:04:14 -07001062 return mImpl.showSessionLocked(args,
1063 sourceFlags
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001064 | VoiceInteractionSession.SHOW_WITH_ASSIST
1065 | VoiceInteractionSession.SHOW_WITH_SCREENSHOT,
Dianne Hackborn17f69352015-07-17 18:04:14 -07001066 showCallback, activityToken);
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001067 } finally {
1068 Binder.restoreCallingIdentity(caller);
1069 }
1070 }
1071 }
1072
1073 @Override
Jorim Jaggib835dd72015-06-08 12:28:42 -07001074 public void hideCurrentSession() throws RemoteException {
1075 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1076 synchronized (this) {
1077 if (mImpl == null) {
1078 return;
1079 }
1080 final long caller = Binder.clearCallingIdentity();
1081 try {
1082 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
1083 try {
1084 mImpl.mActiveSession.mSession.closeSystemDialogs();
1085 } catch (RemoteException e) {
1086 Log.w(TAG, "Failed to call closeSystemDialogs", e);
1087 }
1088 }
1089 } finally {
1090 Binder.restoreCallingIdentity(caller);
1091 }
1092 }
1093 }
1094
1095 @Override
Selim Cineke70d6532015-04-24 16:46:13 -07001096 public void launchVoiceAssistFromKeyguard() {
1097 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1098 synchronized (this) {
1099 if (mImpl == null) {
1100 Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction"
1101 + "service");
1102 return;
1103 }
1104 final long caller = Binder.clearCallingIdentity();
1105 try {
1106 mImpl.launchVoiceAssistFromKeyguard();
1107 } finally {
1108 Binder.restoreCallingIdentity(caller);
1109 }
1110 }
1111 }
1112
1113 @Override
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001114 public boolean isSessionRunning() {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001115 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001116 synchronized (this) {
Jorim Jaggi25e12ab2015-04-02 11:46:28 -07001117 return mImpl != null && mImpl.mActiveSession != null;
1118 }
1119 }
1120
1121 @Override
Jorim Jaggi5f560d02015-04-30 11:49:29 -07001122 public boolean activeServiceSupportsAssist() {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001123 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1124 synchronized (this) {
Selim Cinek03872c02015-05-07 18:12:51 -07001125 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist();
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001126 }
1127 }
1128
1129 @Override
Selim Cineke70d6532015-04-24 16:46:13 -07001130 public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException {
1131 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1132 synchronized (this) {
Selim Cinek03872c02015-05-07 18:12:51 -07001133 return mImpl != null && mImpl.mInfo != null
1134 && mImpl.mInfo.getSupportsLaunchFromKeyguard();
Selim Cineke70d6532015-04-24 16:46:13 -07001135 }
1136 }
1137
1138 @Override
Jorim Jaggi19695d92015-07-20 15:51:40 -07001139 public void onLockscreenShown() {
1140 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1141 synchronized (this) {
1142 if (mImpl == null) {
1143 return;
1144 }
1145 final long caller = Binder.clearCallingIdentity();
1146 try {
1147 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
1148 try {
1149 mImpl.mActiveSession.mSession.onLockscreenShown();
1150 } catch (RemoteException e) {
1151 Log.w(TAG, "Failed to call onLockscreenShown", e);
1152 }
1153 }
1154 } finally {
1155 Binder.restoreCallingIdentity(caller);
1156 }
1157 }
1158 }
1159
1160 @Override
Annie Chinecb9f3e2016-06-27 16:01:52 -07001161 public void registerVoiceInteractionSessionListener(
1162 IVoiceInteractionSessionListener listener) {
1163 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
Annie Chind953ab62016-07-07 11:57:33 -07001164 synchronized (this) {
1165 mVoiceInteractionSessionListeners.register(listener);
1166 }
1167 }
1168
jiayuzhou21a353b2018-08-16 16:09:43 -07001169 @Override
1170 public void getActiveServiceSupportedActions(List<String> voiceActions,
1171 IVoiceActionCheckCallback callback) {
1172 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1173 synchronized (this) {
1174 if (mImpl == null) {
1175 try {
1176 callback.onComplete(null);
1177 } catch (RemoteException e) {
1178 }
1179 return;
1180 }
1181 final long caller = Binder.clearCallingIdentity();
1182 try {
1183 mImpl.getActiveServiceSupportedActions(voiceActions, callback);
1184 } finally {
1185 Binder.restoreCallingIdentity(caller);
1186 }
1187 }
1188 }
1189
Annie Chind953ab62016-07-07 11:57:33 -07001190 public void onSessionShown() {
1191 synchronized (this) {
1192 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
1193 for (int i = 0; i < size; ++i) {
1194 final IVoiceInteractionSessionListener listener =
1195 mVoiceInteractionSessionListeners.getBroadcastItem(i);
1196 try {
1197 listener.onVoiceSessionShown();
1198 } catch (RemoteException e) {
1199 Slog.e(TAG, "Error delivering voice interaction open event.", e);
1200 }
1201 }
1202 mVoiceInteractionSessionListeners.finishBroadcast();
1203 }
1204 }
1205
1206 public void onSessionHidden() {
1207 synchronized (this) {
1208 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
1209 for (int i = 0; i < size; ++i) {
1210 final IVoiceInteractionSessionListener listener =
1211 mVoiceInteractionSessionListeners.getBroadcastItem(i);
1212 try {
1213 listener.onVoiceSessionHidden();
1214
1215 } catch (RemoteException e) {
1216 Slog.e(TAG, "Error delivering voice interaction closed event.", e);
1217 }
1218 }
1219 mVoiceInteractionSessionListeners.finishBroadcast();
Annie Chin2045bdd2016-07-07 10:22:34 -07001220 }
Annie Chinecb9f3e2016-06-27 16:01:52 -07001221 }
1222
1223 @Override
Dianne Hackborn91097de2014-04-04 18:02:06 -07001224 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001225 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Dianne Hackborn18f0d352014-04-25 17:06:18 -07001226 synchronized (this) {
Dianne Hackborn958b9d22015-10-09 16:09:25 -07001227 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
Cedric Hoc663d992015-04-23 15:16:47 -07001228 pw.println(" mEnableService: " + mEnableService);
Dianne Hackborn18f0d352014-04-25 17:06:18 -07001229 if (mImpl == null) {
1230 pw.println(" (No active implementation)");
1231 return;
1232 }
1233 mImpl.dumpLocked(fd, pw, args);
1234 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001235 mSoundTriggerInternal.dump(fd, pw, args);
Dianne Hackborn91097de2014-04-04 18:02:06 -07001236 }
1237
Matt Casey4cff16f2019-01-14 14:56:06 -05001238 @Override
James O'Leary9c9dd982019-02-08 15:49:06 -05001239 public void setUiHints(IVoiceInteractionService service, Bundle hints) {
Matt Casey4cff16f2019-01-14 14:56:06 -05001240 synchronized (this) {
James O'Leary596708b2019-01-30 14:52:21 -05001241 enforceIsCurrentVoiceInteractionService(service);
1242
Matt Casey4cff16f2019-01-14 14:56:06 -05001243 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
1244 for (int i = 0; i < size; ++i) {
1245 final IVoiceInteractionSessionListener listener =
1246 mVoiceInteractionSessionListeners.getBroadcastItem(i);
1247 try {
James O'Leary9c9dd982019-02-08 15:49:06 -05001248 listener.onSetUiHints(hints);
Matt Casey4cff16f2019-01-14 14:56:06 -05001249 } catch (RemoteException e) {
James O'Leary9c9dd982019-02-08 15:49:06 -05001250 Slog.e(TAG, "Error delivering UI hints.", e);
Matt Casey4cff16f2019-01-14 14:56:06 -05001251 }
1252 }
1253 mVoiceInteractionSessionListeners.finishBroadcast();
1254 }
1255 }
1256
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001257 private void enforceCallingPermission(String permission) {
Dianne Hackborn17f69352015-07-17 18:04:14 -07001258 if (mContext.checkCallingOrSelfPermission(permission)
1259 != PackageManager.PERMISSION_GRANTED) {
Jorim Jaggi0b68ff42015-04-02 11:21:39 -07001260 throw new SecurityException("Caller does not hold the permission " + permission);
1261 }
1262 }
1263
James O'Leary596708b2019-01-30 14:52:21 -05001264 private void enforceIsCurrentVoiceInteractionService(IVoiceInteractionService service) {
1265 if (mImpl == null || mImpl.mService == null
1266 || service.asBinder() != mImpl.mService.asBinder()) {
1267 throw new
1268 SecurityException("Caller is not the current voice interaction service");
1269 }
1270 }
1271
Winson Chungbccd4b52017-12-13 11:08:39 -08001272 private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
1273 mImpl = impl;
Wale Ogunwaled0412b32018-05-08 09:25:50 -07001274 mAtmInternal.notifyActiveVoiceInteractionServiceChanged(
Winson Chungbccd4b52017-12-13 11:08:39 -08001275 getActiveServiceComponentName());
1276 }
1277
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001278 class RoleObserver implements OnRoleHoldersChangedListener {
1279 private PackageManager mPm = mContext.getPackageManager();
1280 private RoleManager mRm = mContext.getSystemService(RoleManager.class);
1281
1282 RoleObserver(@NonNull @CallbackExecutor Executor executor) {
1283 mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
Winson Chung28f5a882019-04-08 16:26:03 -07001284 UserHandle currentUser = UserHandle.of(LocalServices.getService(
1285 ActivityManagerInternal.class).getCurrentUserId());
Hai Zhangc00c31e2019-06-03 18:50:33 +00001286 onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001287 }
1288
1289 private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
1290 ResolveInfo resolveInfo = mPm.resolveServiceAsUser(
1291 new Intent(RecognitionService.SERVICE_INTERFACE),
1292 PackageManager.GET_META_DATA, user.getIdentifier());
1293
1294 if (resolveInfo == null || resolveInfo.serviceInfo == null) {
1295 Log.w(TAG, "Unable to resolve default voice recognition service.");
1296 return "";
1297 }
1298
1299 return new ComponentName(resolveInfo.serviceInfo.packageName,
1300 resolveInfo.serviceInfo.name).flattenToShortString();
1301 }
1302
1303 /**
1304 * Convert the assistant-role holder into settings. The rest of the system uses the
1305 * settings.
1306 *
1307 * @param roleName the name of the role whose holders are changed
1308 * @param user the user for this role holder change
1309 */
1310 @Override
1311 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
1312 if (!roleName.equals(RoleManager.ROLE_ASSISTANT)) {
1313 return;
1314 }
1315
1316 List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
1317
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001318 int userId = user.getIdentifier();
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001319 if (roleHolders.isEmpty()) {
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001320 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1321 Settings.Secure.ASSISTANT, "", userId);
1322 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1323 Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
1324 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1325 Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user),
1326 userId);
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001327 } else {
1328 // Assistant is singleton role
1329 String pkg = roleHolders.get(0);
1330
1331 // Try to set role holder as VoiceInteractionService
1332 List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
1333 new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
Winson Chung28f5a882019-04-08 16:26:03 -07001334 PackageManager.GET_META_DATA
1335 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1336 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001337
1338 for (ResolveInfo resolveInfo : services) {
1339 ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1340
1341 VoiceInteractionServiceInfo voiceInteractionServiceInfo =
1342 new VoiceInteractionServiceInfo(mPm, serviceInfo);
1343 if (!voiceInteractionServiceInfo.getSupportsAssist()) {
1344 continue;
1345 }
1346
1347 String serviceComponentName = serviceInfo.getComponentName()
1348 .flattenToShortString();
1349
1350 String serviceRecognizerName = new ComponentName(pkg,
1351 voiceInteractionServiceInfo.getRecognitionService())
1352 .flattenToShortString();
1353
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001354 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1355 Settings.Secure.ASSISTANT, serviceComponentName, userId);
1356 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1357 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
1358 userId);
1359 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1360 Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName,
1361 userId);
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001362
1363 return;
1364 }
1365
1366 // If no service could be found try to set assist activity
1367 final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
1368 new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
Winson Chung28f5a882019-04-08 16:26:03 -07001369 PackageManager.MATCH_DEFAULT_ONLY
1370 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1371 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001372
1373 for (ResolveInfo resolveInfo : activities) {
1374 ActivityInfo activityInfo = resolveInfo.activityInfo;
1375
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001376 Settings.Secure.putStringForUser(getContext().getContentResolver(),
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001377 Settings.Secure.ASSISTANT,
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001378 activityInfo.getComponentName().flattenToShortString(), userId);
1379 Settings.Secure.putStringForUser(getContext().getContentResolver(),
1380 Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
1381 Settings.Secure.putStringForUser(getContext().getContentResolver(),
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001382 Settings.Secure.VOICE_RECOGNITION_SERVICE,
Hai Zhang5cc4ae92019-02-08 11:42:34 -08001383 getDefaultRecognizer(user), userId);
Winson Chung28f5a882019-04-08 16:26:03 -07001384 return;
Philip P. Moltmann5d894502019-01-17 10:31:00 -08001385 }
1386 }
1387 }
1388 }
1389
Dianne Hackborn91097de2014-04-04 18:02:06 -07001390 class SettingsObserver extends ContentObserver {
1391 SettingsObserver(Handler handler) {
1392 super(handler);
1393 ContentResolver resolver = mContext.getContentResolver();
1394 resolver.registerContentObserver(Settings.Secure.getUriFor(
Yohei Yukawa5f531f12015-06-10 21:15:00 -07001395 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
1396 UserHandle.USER_ALL);
Dianne Hackborn91097de2014-04-04 18:02:06 -07001397 }
1398
1399 @Override public void onChange(boolean selfChange) {
1400 synchronized (VoiceInteractionManagerServiceStub.this) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001401 switchImplementationIfNeededLocked(false);
Dianne Hackborn91097de2014-04-04 18:02:06 -07001402 }
1403 }
1404 }
1405
1406 PackageMonitor mPackageMonitor = new PackageMonitor() {
1407 @Override
1408 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001409 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
1410
1411 int userHandle = UserHandle.getUserId(uid);
1412 ComponentName curInteractor = getCurInteractor(userHandle);
1413 ComponentName curRecognizer = getCurRecognizer(userHandle);
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001414 boolean hitInt = false;
1415 boolean hitRec = false;
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001416 for (String pkg : packages) {
1417 if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001418 hitInt = true;
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001419 break;
1420 } else if (curRecognizer != null
1421 && pkg.equals(curRecognizer.getPackageName())) {
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001422 hitRec = true;
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001423 break;
1424 }
1425 }
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001426 if (hitInt && doit) {
1427 // The user is force stopping our current interactor.
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001428 // Clear the current settings and restore default state.
Amith Yamasanif5c37eb2016-05-23 17:21:08 -07001429 synchronized (VoiceInteractionManagerServiceStub.this) {
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001430 Slog.i(TAG, "Force stopping current voice interactor: "
1431 + getCurInteractor(userHandle));
Chris Thorntonf967da92016-05-02 19:22:57 -07001432 unloadAllKeyphraseModels();
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001433 if (mImpl != null) {
1434 mImpl.shutdownLocked();
Winson Chungbccd4b52017-12-13 11:08:39 -08001435 setImplLocked(null);
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001436 }
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001437
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001438 setCurInteractor(null, userHandle);
1439 setCurRecognizer(null, userHandle);
Jorim Jaggicc3a46a2015-06-25 15:55:43 -07001440 resetCurAssistant(userHandle);
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001441 initForUser(userHandle);
1442 switchImplementationIfNeededLocked(true);
Hai Zhang7f1b8f62019-03-08 16:44:27 -08001443
1444 Context context = getContext();
1445 context.getSystemService(RoleManager.class).clearRoleHoldersAsUser(
1446 RoleManager.ROLE_ASSISTANT, 0, UserHandle.of(userHandle),
1447 context.getMainExecutor(), successful -> {
1448 if (!successful) {
1449 Slog.e(TAG,
1450 "Failed to clear default assistant for force stop");
1451 }
1452 });
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001453 }
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001454 } else if (hitRec && doit) {
1455 // We are just force-stopping the current recognizer, which is not
1456 // also the current interactor.
1457 synchronized (VoiceInteractionManagerServiceStub.this) {
1458 Slog.i(TAG, "Force stopping current voice recognizer: "
1459 + getCurRecognizer(userHandle));
1460 initSimpleRecognizer(null, userHandle);
1461 }
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001462 }
Dianne Hackborn3d7ab612018-12-17 10:53:53 -08001463 return hitInt || hitRec;
Dianne Hackborn91097de2014-04-04 18:02:06 -07001464 }
1465
1466 @Override
1467 public void onHandleUserStop(Intent intent, int userHandle) {
Dianne Hackborn91097de2014-04-04 18:02:06 -07001468 }
1469
1470 @Override
Sudheer Shanka7a3d9012017-04-11 17:19:22 -07001471 public void onPackageModified(String pkgName) {
1472 // If the package modified is not in the current user, then don't bother making
1473 // any changes as we are going to do any initialization needed when we switch users.
1474 if (mCurUser != getChangingUserId()) {
1475 return;
1476 }
1477 // Package getting updated will be handled by {@link #onSomePackagesChanged}.
1478 if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
1479 return;
1480 }
1481 final ComponentName curInteractor = getCurInteractor(mCurUser);
1482 if (curInteractor == null) {
1483 final VoiceInteractionServiceInfo availInteractorInfo
1484 = findAvailInteractor(mCurUser, pkgName);
1485 if (availInteractorInfo != null) {
1486 final ComponentName availInteractor = new ComponentName(
1487 availInteractorInfo.getServiceInfo().packageName,
1488 availInteractorInfo.getServiceInfo().name);
1489 setCurInteractor(availInteractor, mCurUser);
1490 if (getCurRecognizer(mCurUser) == null &&
1491 availInteractorInfo.getRecognitionService() != null) {
1492 setCurRecognizer(new ComponentName(
1493 availInteractorInfo.getServiceInfo().packageName,
1494 availInteractorInfo.getRecognitionService()), mCurUser);
1495 }
1496 }
1497 } else {
1498 if (didSomePackagesChange()) {
1499 // Package is changed
1500 if (curInteractor != null && pkgName.equals(
1501 curInteractor.getPackageName())) {
1502 switchImplementationIfNeeded(true);
1503 }
1504 } else {
1505 // Only some components are changed
1506 if (curInteractor != null
1507 && isComponentModified(curInteractor.getClassName())) {
1508 switchImplementationIfNeeded(true);
1509 }
1510 }
1511 }
1512 }
1513
1514 @Override
Dianne Hackborn91097de2014-04-04 18:02:06 -07001515 public void onSomePackagesChanged() {
Dianne Hackborna351ab92014-08-08 17:35:50 -07001516 int userHandle = getChangingUserId();
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001517 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -07001518
Amith Yamasanif5c37eb2016-05-23 17:21:08 -07001519 synchronized (VoiceInteractionManagerServiceStub.this) {
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001520 ComponentName curInteractor = getCurInteractor(userHandle);
1521 ComponentName curRecognizer = getCurRecognizer(userHandle);
Dianne Hackborne9563652016-08-18 17:33:41 -07001522 ComponentName curAssistant = getCurAssistant(userHandle);
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001523 if (curRecognizer == null) {
1524 // Could a new recognizer appear when we don't have one pre-installed?
1525 if (anyPackagesAppearing()) {
1526 curRecognizer = findAvailRecognizer(null, userHandle);
1527 if (curRecognizer != null) {
1528 setCurRecognizer(curRecognizer, userHandle);
1529 }
Dianne Hackborna351ab92014-08-08 17:35:50 -07001530 }
Dianne Hackborna351ab92014-08-08 17:35:50 -07001531 return;
1532 }
1533
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001534 if (curInteractor != null) {
1535 int change = isPackageDisappearing(curInteractor.getPackageName());
1536 if (change == PACKAGE_PERMANENT_CHANGE) {
1537 // The currently set interactor is permanently gone; fall back to
1538 // the default config.
1539 setCurInteractor(null, userHandle);
1540 setCurRecognizer(null, userHandle);
Dianne Hackborne9563652016-08-18 17:33:41 -07001541 resetCurAssistant(userHandle);
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001542 initForUser(userHandle);
1543 return;
Dianne Hackborna351ab92014-08-08 17:35:50 -07001544 }
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001545
1546 change = isPackageAppearing(curInteractor.getPackageName());
1547 if (change != PACKAGE_UNCHANGED) {
1548 // If current interactor is now appearing, for any reason, then
1549 // restart our connection with it.
1550 if (mImpl != null && curInteractor.getPackageName().equals(
1551 mImpl.mComponent.getPackageName())) {
1552 switchImplementationIfNeededLocked(true);
1553 }
1554 }
1555 return;
Dianne Hackborna351ab92014-08-08 17:35:50 -07001556 }
Dianne Hackborna351ab92014-08-08 17:35:50 -07001557
Dianne Hackborne9563652016-08-18 17:33:41 -07001558 if (curAssistant != null) {
1559 int change = isPackageDisappearing(curAssistant.getPackageName());
1560 if (change == PACKAGE_PERMANENT_CHANGE) {
1561 // If the currently set assistant is being removed, then we should
1562 // reset back to the default state (which is probably that we prefer
1563 // to have the default full voice interactor enabled).
1564 setCurInteractor(null, userHandle);
1565 setCurRecognizer(null, userHandle);
1566 resetCurAssistant(userHandle);
1567 initForUser(userHandle);
1568 return;
1569 }
1570 }
1571
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001572 // There is no interactor, so just deal with a simple recognizer.
1573 int change = isPackageDisappearing(curRecognizer.getPackageName());
1574 if (change == PACKAGE_PERMANENT_CHANGE
1575 || change == PACKAGE_TEMPORARY_CHANGE) {
1576 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
Dianne Hackborna351ab92014-08-08 17:35:50 -07001577
Dianne Hackbornb8004ff2015-06-15 13:35:16 -07001578 } else if (isPackageModified(curRecognizer.getPackageName())) {
1579 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
1580 userHandle), userHandle);
1581 }
Dianne Hackborna351ab92014-08-08 17:35:50 -07001582 }
Dianne Hackborn91097de2014-04-04 18:02:06 -07001583 }
1584 };
1585 }
1586}