Merge "Set assistant as a role"

This commit is contained in:
Philip P. Moltmann
2019-01-24 20:51:41 +00:00
committed by Android (Google) Code Review
12 changed files with 146 additions and 54 deletions

View File

@@ -1053,6 +1053,7 @@ package android.app.role {
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
}
public interface RoleManagerCallback {

View File

@@ -14,6 +14,10 @@ package android {
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
}
public static final class R.array {
field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
}
}
package android.animation {
@@ -332,6 +336,7 @@ package android.app.role {
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
}
public interface RoleManagerCallback {

View File

@@ -171,6 +171,15 @@ public final class RoleManager {
*/
public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
/**
* The name of the assistant app role.
*
* @hide
*/
@SystemApi
@TestApi
public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
/**
* The action used to request user approval of a role for an application.
*

View File

@@ -7812,6 +7812,9 @@ public final class Settings {
* or an activity that handles ACTION_ASSIST, or empty which means using the default
* handling.
*
* <p>This should be set indirectly by setting the {@link
* android.app.role.RoleManager#ROLE_ASSISTANT assistant role}.
*
* @hide
*/
@UnsupportedAppUsage

View File

@@ -17,13 +17,10 @@
package com.android.internal.app;
import android.annotation.NonNull;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,8 +28,6 @@ import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
import com.android.internal.R;
import java.util.ArrayList;
import java.util.Set;
@@ -44,14 +39,6 @@ public class AssistUtils {
private static final String TAG = "AssistUtils";
/**
* Sentinel value for "no default assistant specified."
*
* Empty string is already used to represent an explicit setting of No Assistant. null cannot
* be used because we can't represent a null value in XML.
*/
private static final String UNSET = "#+UNSET";
private final Context mContext;
private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
@@ -186,37 +173,9 @@ public class AssistUtils {
Settings.Secure.ASSISTANT, userId);
if (setting != null) {
return ComponentName.unflattenFromString(setting);
}
final String defaultSetting = mContext.getResources().getString(
R.string.config_defaultAssistantComponentName);
if (defaultSetting != null && !defaultSetting.equals(UNSET)) {
return ComponentName.unflattenFromString(defaultSetting);
}
// Fallback to keep backward compatible behavior when there is no user setting.
if (activeServiceSupportsAssistGesture()) {
return getActiveServiceComponentName();
}
if (UNSET.equals(defaultSetting)) {
} else {
return null;
}
final SearchManager searchManager =
(SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
if (searchManager == null) {
return null;
}
final Intent intent = searchManager.getAssistIntent(false);
PackageManager pm = mContext.getPackageManager();
ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY,
userId);
if (info != null) {
return new ComponentName(info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
}
return null;
}
public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) {

View File

@@ -3729,9 +3729,6 @@
<!-- Whether or not the "SMS app service" feature is enabled -->
<bool name="config_useSmsAppService">true</bool>
<!-- Component name for default assistant on this device -->
<string name="config_defaultAssistantComponentName">#+UNSET</string>
<!-- Class name for the InputEvent compatibility processor override.
Empty string means use the default compatibility processor
(android.view.InputEventCompatProcessor). -->

View File

@@ -2988,7 +2988,7 @@
</public-group>
<public-group type="array" first-id="0x01070006">
<!-- @hide @SystemApi -->
<!-- @hide @TestApi @SystemApi -->
<public name="config_defaultRoleHolders" />
</public-group>

View File

@@ -3528,8 +3528,6 @@
<java-symbol type="bool" name="config_useSmsAppService" />
<java-symbol type="string" name="config_defaultAssistantComponentName" />
<java-symbol type="id" name="transition_overlay_view_tag" />
<java-symbol type="dimen" name="rounded_corner_radius" />

View File

@@ -18,6 +18,7 @@ package com.android.server.policy.role;
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 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
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();

View File

@@ -198,6 +198,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
// 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

View File

@@ -1561,6 +1561,12 @@ public final class SystemServer {
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
@@ -2011,12 +2017,6 @@ public final class SystemServer {
}
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";

View File

@@ -17,13 +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 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;
@@ -78,6 +83,7 @@ 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.
@@ -200,6 +206,7 @@ public class VoiceInteractionManagerService extends SystemService {
VoiceInteractionManagerServiceStub() {
mEnableService = shouldEnableService(mContext);
new RoleObserver(mContext.getMainExecutor());
}
// TODO: VI Make sure the caller is the current user or profile
@@ -1268,6 +1275,106 @@ public class VoiceInteractionManagerService extends SystemService {
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);