am 01e26f94: am 47df503b: Fix issues 16739817 and 16709247 in voice interaction service.

* commit '01e26f94754c00d5185aeb32c663cf89ce74be0e':
  Fix issues 16739817 and 16709247 in voice interaction service.
This commit is contained in:
Dianne Hackborn
2014-08-09 20:40:54 +00:00
committed by Android Git Automerger
5 changed files with 227 additions and 201 deletions

View File

@@ -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 "

View File

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

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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<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) {
@@ -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);
}
}
};
}