diff options
author | Dianne Hackborn <hackbod@google.com> | 2014-08-08 17:35:50 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2014-08-09 13:31:59 -0700 |
commit | a351ab96987381ffe7ea29a7cdec1e7fbd1497d5 (patch) | |
tree | 8cec8f73970a6b7fa81e6e279080d76d065e5185 | |
parent | d78e8114988326d557a1405e669b330f63fbf0d3 (diff) | |
download | frameworks_base-a351ab96987381ffe7ea29a7cdec1e7fbd1497d5.zip frameworks_base-a351ab96987381ffe7ea29a7cdec1e7fbd1497d5.tar.gz frameworks_base-a351ab96987381ffe7ea29a7cdec1e7fbd1497d5.tar.bz2 |
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
5 files changed, 224 insertions, 198 deletions
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java index d27e2cd..bacda04 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 60d38ae..0000000 --- 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<ResolveInfo> 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<numAvailable; i++) { - ServiceInfo serviceInfo = available.get(i).serviceInfo; - if (prefPackage.equals(serviceInfo.packageName)) { - return new ComponentName(serviceInfo.packageName, serviceInfo.name); - } - } - } - if (numAvailable > 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 1d684df..22d8e32 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 e8d6773..e70f0cf 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; @@ -1117,11 +1108,6 @@ public final class SystemServer { 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) { reportWtf("Notifying AudioService running", e); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 0d24793..cd3684b 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; @@ -85,6 +95,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<ResolveInfo> 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<numAvailable; i++) { + ServiceInfo cur = available.get(i).serviceInfo; + if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + if (serviceInfo == null) { + serviceInfo = cur; + } else { + Slog.w(TAG, "more than one voice interaction service, picking first " + + new ComponentName(serviceInfo.packageName, serviceInfo.name) + + " over " + + new ComponentName(cur.packageName, cur.name)); + } + } + } + + return serviceInfo != null ? + new ComponentName(serviceInfo.packageName, serviceInfo.name) : null; + } + } + + ComponentName getCurInteractor(int userHandle) { + String curInteractor = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); + if (TextUtils.isEmpty(curInteractor)) { + return null; + } + if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor + + " user=" + userHandle); + return ComponentName.unflattenFromString(curInteractor); + } + + void setCurInteractor(ComponentName comp, int userHandle) { + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, + comp != null ? comp.flattenToShortString() : "", userHandle); + if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp + + " user=" + userHandle); + } + + ComponentName findAvailRecognizer(String prefPackage, int userHandle) { + List<ResolveInfo> 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<numAvailable; i++) { + ServiceInfo serviceInfo = available.get(i).serviceInfo; + if (prefPackage.equals(serviceInfo.packageName)) { + return new ComponentName(serviceInfo.packageName, serviceInfo.name); + } + } + } + if (numAvailable > 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) { @@ -461,22 +629,56 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void onPackageDisappeared(String packageName, int reason) { - } + 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; + } - @Override - public void onPackageAppeared(String packageName, int reason) { - if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) { - switchImplementationIfNeededLocked(true); + 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; } - } - @Override - public void onPackageModified(String packageName) { - } + // 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); - @Override - public void onSomePackagesChanged() { + } else if (isPackageModified(curRecognizer.getPackageName())) { + setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), + userHandle), userHandle); + } } }; } |