From a351ab96987381ffe7ea29a7cdec1e7fbd1497d5 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 8 Aug 2014 17:35:50 -0700 Subject: [PATCH] Fix issues 16739817 and 16709247 in voice interaction service. Issue #16739817 VIS doesn't start for non-primary user(s) Issue #16709247 GSA is not the default voice interaction agent These are both fixed by getting rid of the existing code for applying the default voice recognizer, moving it in to the voice interaction manager service, and extending it to also set up the default voice interaction service. Change-Id: If8d5936c28aebfa7eff77c8d99241c3a2ffdb0a4 --- .../voice/VoiceInteractionServiceInfo.java | 9 +- .../server/RecognitionManagerService.java | 169 ------------- .../server/am/ActivityManagerService.java | 2 +- .../java/com/android/server/SystemServer.java | 14 -- .../VoiceInteractionManagerService.java | 234 ++++++++++++++++-- 5 files changed, 227 insertions(+), 201 deletions(-) delete mode 100644 services/core/java/com/android/server/RecognitionManagerService.java diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java index d27e2cd91061f..bacda0486daaa 100644 --- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java +++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java @@ -17,13 +17,14 @@ package android.service.voice; import android.Manifest; +import android.app.AppGlobals; import android.content.ComponentName; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.speech.RecognitionService; +import android.os.RemoteException; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; @@ -48,6 +49,12 @@ public class VoiceInteractionServiceInfo { this(pm, pm.getServiceInfo(comp, PackageManager.GET_META_DATA)); } + public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp, int userHandle) + throws PackageManager.NameNotFoundException, RemoteException { + this(pm, AppGlobals.getPackageManager().getServiceInfo(comp, + PackageManager.GET_META_DATA, userHandle)); + } + public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) { if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) { mParseError = "Service does not require permission " diff --git a/services/core/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java deleted file mode 100644 index 60d38ae1c050b..0000000000000 --- a/services/core/java/com/android/server/RecognitionManagerService.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import com.android.internal.content.PackageMonitor; - -import android.app.AppGlobals; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.IPackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.os.Binder; -import android.os.RemoteException; -import android.os.UserHandle; -import android.provider.Settings; -import android.speech.RecognitionService; -import android.text.TextUtils; -import android.util.Slog; - -import java.util.List; - -public class RecognitionManagerService extends Binder { - final static String TAG = "RecognitionManagerService"; - - private final Context mContext; - private final MyPackageMonitor mMonitor; - private final IPackageManager mIPm; - - private static final boolean DEBUG = false; - - class MyPackageMonitor extends PackageMonitor { - public void onSomePackagesChanged() { - int userHandle = getChangingUserId(); - if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle); - ComponentName comp = getCurRecognizer(userHandle); - if (comp == null) { - if (anyPackagesAppearing()) { - comp = findAvailRecognizer(null, userHandle); - if (comp != null) { - setCurRecognizer(comp, userHandle); - } - } - return; - } - - int change = isPackageDisappearing(comp.getPackageName()); - if (change == PACKAGE_PERMANENT_CHANGE - || change == PACKAGE_TEMPORARY_CHANGE) { - setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); - - } else if (isPackageModified(comp.getPackageName())) { - setCurRecognizer(findAvailRecognizer(comp.getPackageName(), userHandle), - userHandle); - } - } - } - - RecognitionManagerService(Context context) { - mContext = context; - mMonitor = new MyPackageMonitor(); - mMonitor.register(context, null, UserHandle.ALL, true); - mIPm = AppGlobals.getPackageManager(); - IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, - filter, null, null); - } - - public void systemReady() { - initForUser(UserHandle.USER_OWNER); - } - - private void initForUser(int userHandle) { - if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle); - ComponentName comp = getCurRecognizer(userHandle); - ServiceInfo info = null; - if (comp != null) { - // See if the current recognizer is still available. - try { - info = mIPm.getServiceInfo(comp, 0, userHandle); - } catch (RemoteException e) { - } - } - if (info == null) { - comp = findAvailRecognizer(null, userHandle); - if (comp != null) { - setCurRecognizer(comp, userHandle); - } - } - } - - ComponentName findAvailRecognizer(String prefPackage, int userHandle) { - List available = - mContext.getPackageManager().queryIntentServicesAsUser( - new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle); - int numAvailable = available.size(); - - if (numAvailable == 0) { - Slog.w(TAG, "no available voice recognition services found for user " + userHandle); - return null; - } else { - if (prefPackage != null) { - for (int i=0; i 1) { - Slog.w(TAG, "more than one voice recognition service found, picking first"); - } - - ServiceInfo serviceInfo = available.get(0).serviceInfo; - return new ComponentName(serviceInfo.packageName, serviceInfo.name); - } - } - - ComponentName getCurRecognizer(int userHandle) { - String curRecognizer = Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); - if (TextUtils.isEmpty(curRecognizer)) { - return null; - } - if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer - + " user=" + userHandle); - return ComponentName.unflattenFromString(curRecognizer); - } - - void setCurRecognizer(ComponentName comp, int userHandle) { - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, - comp != null ? comp.flattenToShortString() : "", userHandle); - if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp - + " user=" + userHandle); - } - - BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DEBUG) Slog.i(TAG, "received " + action); - if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { - int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - if (userHandle > 0) { - initForUser(userHandle); - } - } - } - }; -} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1d684df86e18b..22d8e32d874c1 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -17327,7 +17327,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Booting up a new user, need to tell system services about it. // Note that this is on the same handler as scheduling of broadcasts, // which is important because it needs to go first. - mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId)); + mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0)); } if (foreground) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index e8d67737478fa..e70f0cf379670 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -402,7 +402,6 @@ public final class SystemServer { BluetoothManagerService bluetooth = null; UsbService usb = null; SerialService serial = null; - RecognitionManagerService recognition = null; NetworkTimeUpdateService networkTimeUpdater = null; CommonTimeManagementService commonTimeMgmtService = null; InputManagerService inputManager = null; @@ -843,13 +842,6 @@ public final class SystemServer { mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS); } - try { - Slog.i(TAG, "Recognition Service"); - recognition = new RecognitionManagerService(context); - } catch (Throwable e) { - reportWtf("starting Recognition Service", e); - } - if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) { mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS); } @@ -1046,7 +1038,6 @@ public final class SystemServer { final NetworkScoreService networkScoreF = networkScore; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; - final RecognitionManagerService recognitionF = recognition; final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; @@ -1116,11 +1107,6 @@ public final class SystemServer { } catch (Throwable e) { reportWtf("making Connectivity Service ready", e); } - try { - if (recognitionF != null) recognitionF.systemReady(); - } catch (Throwable e) { - reportWtf("making Recognition Service ready", e); - } try { if (audioServiceF != null) audioServiceF.systemReady(); } catch (Throwable e) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 0d2479351954c..cd3684b17769d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -18,11 +18,16 @@ package com.android.server.voiceinteraction; import android.Manifest; import android.app.ActivityManager; +import android.app.AppGlobals; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; @@ -38,7 +43,11 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; +import android.service.voice.VoiceInteractionService; +import android.service.voice.VoiceInteractionServiceInfo; +import android.speech.RecognitionService; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.Slog; import com.android.internal.app.IVoiceInteractionManagerService; @@ -50,13 +59,14 @@ import com.android.server.UiThread; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.List; /** * SystemService that publishes an IVoiceInteractionManagerService. */ public class VoiceInteractionManagerService extends SystemService { - static final String TAG = "VoiceInteractionManagerService"; + static final boolean DEBUG = false; final Context mContext; final ContentResolver mResolver; @@ -84,6 +94,11 @@ public class VoiceInteractionManagerService extends SystemService { } } + @Override + public void onStartUser(int userHandle) { + mServiceStub.initForUser(userHandle); + } + @Override public void onSwitchUser(int userHandle) { mServiceStub.switchUser(userHandle); @@ -115,6 +130,60 @@ public class VoiceInteractionManagerService extends SystemService { } } + public void initForUser(int userHandle) { + if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle); + ComponentName curInteractor = getCurInteractor(userHandle); + ComponentName curRecognizer = getCurRecognizer(userHandle); + if (curRecognizer != null) { + // If we already have at least a recognizer, then we probably want to + // leave things as they are... unless something has disappeared. + IPackageManager pm = AppGlobals.getPackageManager(); + ServiceInfo interactorInfo = null; + ServiceInfo recognizerInfo = null; + try { + recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle); + if (curInteractor != null) { + interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle); + } + } catch (RemoteException e) { + } + // If the apps for the currently set components still exist, then all is okay. + if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { + return; + } + } + + // Initializing settings, look for an interactor first. + curInteractor = findAvailInteractor(userHandle); + if (curInteractor != null) { + try { + VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( + mContext.getPackageManager(), curInteractor, userHandle); + if (info.getParseError() == null) { + setCurInteractor(curInteractor, userHandle); + if (info.getRecognitionService() != null) { + // Eventually it will be an error to not specify this. + curRecognizer = new ComponentName(info.getServiceInfo().packageName, + info.getRecognitionService()); + setCurRecognizer(curRecognizer, userHandle); + return; + } + } else { + Slog.w(TAG, "Bad interaction service " + curInteractor + ": " + + info.getParseError()); + } + } catch (PackageManager.NameNotFoundException e) { + } catch (RemoteException e) { + } + } + + // No voice interactor, we'll just set up a simple recognizer. + curRecognizer = findAvailRecognizer(null, userHandle); + if (curRecognizer != null) { + setCurRecognizer(curRecognizer, userHandle); + } + } + public void systemRunning(boolean safeMode) { mSafeMode = safeMode; @@ -165,6 +234,105 @@ public class VoiceInteractionManagerService extends SystemService { } } + ComponentName findAvailInteractor(int userHandle) { + List available = + mContext.getPackageManager().queryIntentServicesAsUser( + new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle); + int numAvailable = available.size(); + + if (numAvailable == 0) { + Slog.w(TAG, "no available voice interaction services found for user " + userHandle); + return null; + } else { + // Find first system package. We never want to allow third party services to + // be automatically selected, because those require approval of the user. + ServiceInfo serviceInfo = null; + for (int i=0; i 1) { + Slog.w(TAG, "more than one voice recognition service found, picking first"); + } + + ServiceInfo serviceInfo = available.get(0).serviceInfo; + return new ComponentName(serviceInfo.packageName, serviceInfo.name); + } + } + + ComponentName getCurRecognizer(int userHandle) { + String curRecognizer = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); + if (TextUtils.isEmpty(curRecognizer)) { + return null; + } + if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer + + " user=" + userHandle); + return ComponentName.unflattenFromString(curRecognizer); + } + + void setCurRecognizer(ComponentName comp, int userHandle) { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + comp != null ? comp.flattenToShortString() : "", userHandle); + if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp + + " user=" + userHandle); + } + @Override public void startSession(IVoiceInteractionService service, Bundle args) { synchronized (this) { @@ -460,23 +628,57 @@ public class VoiceInteractionManagerService extends SystemService { public void onHandleUserStop(Intent intent, int userHandle) { } - @Override - public void onPackageDisappeared(String packageName, int reason) { - } - - @Override - public void onPackageAppeared(String packageName, int reason) { - if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) { - switchImplementationIfNeededLocked(true); - } - } - - @Override - public void onPackageModified(String packageName) { - } - @Override public void onSomePackagesChanged() { + int userHandle = getChangingUserId(); + if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle); + + ComponentName curInteractor = getCurInteractor(userHandle); + ComponentName curRecognizer = getCurRecognizer(userHandle); + if (curRecognizer == null) { + // Could a new recognizer appear when we don't have one pre-installed? + if (anyPackagesAppearing()) { + curRecognizer = findAvailRecognizer(null, userHandle); + if (curRecognizer != null) { + setCurRecognizer(curRecognizer, userHandle); + } + } + return; + } + + if (curInteractor != null) { + int change = isPackageDisappearing(curInteractor.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE) { + // The currently set interactor is permanently gone; fall back to + // the default config. + setCurInteractor(null, userHandle); + setCurRecognizer(null, userHandle); + initForUser(userHandle); + return; + } + + change = isPackageAppearing(curInteractor.getPackageName()); + if (change != PACKAGE_UNCHANGED) { + // If current interactor is now appearing, for any reason, then + // restart our connection with it. + if (mImpl != null && curInteractor.getPackageName().equals( + mImpl.mComponent.getPackageName())) { + switchImplementationIfNeededLocked(true); + } + } + return; + } + + // There is no interactor, so just deal with a simple recognizer. + int change = isPackageDisappearing(curRecognizer.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); + + } else if (isPackageModified(curRecognizer.getPackageName())) { + setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), + userHandle), userHandle); + } } }; }