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); + } } }; }