Set assistant as a role
- Register a role observer in VoiceInteractionManagerService. Once the
role is changes map the new role setting onto the old settings.
- As the assistant role is now always set, there is no need to have code
in AssistUtil for the case the assistant setting is not set
- Remove old config option for the default assistant. The default
assistant is not configured via the roles config
Bug: 110557011
Test: - Set, unset and swtiched assistant via the settings UI
- for voice interaction service
- for assist activity
- Booted from freshly wiped device and saw assitant to be set to
default
Change-Id: I8596f49c6f6496e8b70cf3236aaa7d7557443a93
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 055c941..7f2dedb 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.app.role.RoleManager;
+import android.content.ComponentName;
import android.content.Context;
import android.os.Debug;
import android.provider.Settings;
@@ -90,6 +91,17 @@
return CollectionUtils.singletonOrEmpty(result);
}
+ case RoleManager.ROLE_ASSISTANT: {
+ String legacyAssistant = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
+
+ if (legacyAssistant == null || legacyAssistant.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return Collections.singletonList(
+ ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+ }
+ }
default: {
Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
return Collections.emptyList();
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c0517fd..1c7596b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -198,6 +198,7 @@
// Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
// for a given role before adding a migration statement for it here
migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+ migrateRoleIfNecessary(RoleManager.ROLE_ASSISTANT, userId);
// Some vital packages state has changed since last role grant
// Run grants again
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cef47ca..279e55e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1546,6 +1546,12 @@
traceEnd();
}
+ // Grants default permissions and defines roles
+ traceBeginAndSlog("StartRoleManagerService");
+ mSystemServiceManager.startService(new RoleManagerService(
+ mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
+ traceEnd();
+
// We need to always start this service, regardless of whether the
// FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
// of initializing various settings. It will internally modify its behavior
@@ -1996,12 +2002,6 @@
}
traceEnd();
- // Grants default permissions and defines roles
- traceBeginAndSlog("StartRoleManagerService");
- mSystemServiceManager.startService(new RoleManagerService(
- mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
- traceEnd();
-
// No dependency on Webview preparation in system server. But this should
// be completed before allowing 3rd party
final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 613c4ff..94b6a10 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -17,16 +17,18 @@
package com.android.server.voiceinteraction;
import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-
-import com.android.internal.app.IVoiceActionCheckCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
import android.app.AppGlobals;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -62,8 +64,9 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.app.IVoiceInteractionSessionListener;
+import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.PackageMonitor;
@@ -75,10 +78,12 @@
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.soundtrigger.SoundTriggerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* SystemService that publishes an IVoiceInteractionManagerService.
@@ -201,6 +206,7 @@
VoiceInteractionManagerServiceStub() {
mEnableService = shouldEnableService(mContext);
+ new RoleObserver(mContext.getMainExecutor());
}
// TODO: VI Make sure the caller is the current user or profile
@@ -1218,6 +1224,106 @@
getActiveServiceComponentName());
}
+ class RoleObserver implements OnRoleHoldersChangedListener {
+ private PackageManager mPm = mContext.getPackageManager();
+ private RoleManager mRm = mContext.getSystemService(RoleManager.class);
+
+ RoleObserver(@NonNull @CallbackExecutor Executor executor) {
+ mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
+ }
+
+ private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
+ ResolveInfo resolveInfo = mPm.resolveServiceAsUser(
+ new Intent(RecognitionService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA, user.getIdentifier());
+
+ if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+ Log.w(TAG, "Unable to resolve default voice recognition service.");
+ return "";
+ }
+
+ return new ComponentName(resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name).flattenToShortString();
+ }
+
+ /**
+ * Convert the assistant-role holder into settings. The rest of the system uses the
+ * settings.
+ *
+ * @param roleName the name of the role whose holders are changed
+ * @param user the user for this role holder change
+ */
+ @Override
+ public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+ if (!roleName.equals(RoleManager.ROLE_ASSISTANT)) {
+ return;
+ }
+
+ List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
+
+ if (roleHolders.isEmpty()) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ASSISTANT, "");
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user));
+ } else {
+ // Assistant is singleton role
+ String pkg = roleHolders.get(0);
+
+ // Try to set role holder as VoiceInteractionService
+ List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
+ new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
+ PackageManager.GET_META_DATA, user.getIdentifier());
+
+ for (ResolveInfo resolveInfo : services) {
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+ VoiceInteractionServiceInfo voiceInteractionServiceInfo =
+ new VoiceInteractionServiceInfo(mPm, serviceInfo);
+ if (!voiceInteractionServiceInfo.getSupportsAssist()) {
+ continue;
+ }
+
+ String serviceComponentName = serviceInfo.getComponentName()
+ .flattenToShortString();
+
+ String serviceRecognizerName = new ComponentName(pkg,
+ voiceInteractionServiceInfo.getRecognitionService())
+ .flattenToShortString();
+
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ASSISTANT, serviceComponentName);
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
+
+ return;
+ }
+
+ // If no service could be found try to set assist activity
+ final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
+ new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
+ PackageManager.MATCH_DEFAULT_ONLY, user.getIdentifier());
+
+ for (ResolveInfo resolveInfo : activities) {
+ ActivityInfo activityInfo = resolveInfo.activityInfo;
+
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ASSISTANT,
+ activityInfo.getComponentName().flattenToShortString());
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ getDefaultRecognizer(user));
+ }
+ }
+ }
+ }
+
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);