Allows a plugin Settings activity to designate plugins it supports.

The activity can add categories to its intent filter which
match the actions of the plugins it supports. The Settings
icon is only shown next to these plugins.

This is useful if an app (e.g. SupportApp) implements
multiple plugins which may each want their own settings.

Note: If any settings activity in an app specifies
categories of plugin it supports, any other settings
activities in the same app must also provide categories
of their plugins to disambiguate.

Test: Manually with SupportApp (including mix of plugins
with and without Settings activities) and AwarenessSpace
plugin (with a non-categorized settings activity).

Change-Id: If3ab7b5f7f916fd3f6b05b89cf1a22c9d21403cc
This commit is contained in:
Andy Wickham
2021-02-01 14:13:00 -08:00
parent 80466c081a
commit 2b14f4bfd4

View File

@@ -15,7 +15,10 @@
*/
package com.android.launcher3.settings;
import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
@@ -26,10 +29,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -130,7 +131,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
EditText filterBox = view.findViewById(R.id.filter_box);
filterBox.setVisibility(View.VISIBLE);
filterBox.setVisibility(VISIBLE);
filterBox.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@@ -212,7 +213,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
Set<String> pluginActions = manager.getPluginActions();
ArrayMap<Pair<String, String>, ArrayList<Pair<String, ServiceInfo>>> plugins =
ArrayMap<Pair<String, String>, ArrayList<Pair<String, ResolveInfo>>> plugins =
new ArrayMap<>();
Set<String> pluginPermissionApps = pm.getPackagesHoldingPermissions(
@@ -224,7 +225,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
for (String action : pluginActions) {
String name = toName(action);
List<ResolveInfo> result = pm.queryIntentServices(
new Intent(action), MATCH_DISABLED_COMPONENTS);
new Intent(action), MATCH_DISABLED_COMPONENTS | GET_RESOLVED_FILTER);
for (ResolveInfo info : result) {
String packageName = info.serviceInfo.packageName;
if (!pluginPermissionApps.contains(packageName)) {
@@ -235,7 +236,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
if (!plugins.containsKey(key)) {
plugins.put(key, new ArrayList<>());
}
plugins.get(key).add(Pair.create(name, info.serviceInfo));
plugins.get(key).add(Pair.create(name, info));
}
}
@@ -243,11 +244,11 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
plugins.forEach((key, si) -> {
String packageName = key.first;
List<ComponentName> componentNames = si.stream()
.map(p -> new ComponentName(packageName, p.second.name))
.map(p -> new ComponentName(packageName, p.second.serviceInfo.name))
.collect(Collectors.toList());
if (!componentNames.isEmpty()) {
SwitchPreference pref = new PluginPreference(
prefContext, si.get(0).second.applicationInfo, enabler, componentNames);
prefContext, si.get(0).second, enabler, componentNames);
pref.setSummary("Plugins: "
+ si.stream().map(p -> p.first).collect(Collectors.joining(", ")));
mPluginsCategory.addPreference(pref);
@@ -341,21 +342,33 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
}
private static class PluginPreference extends SwitchPreference {
private final boolean mHasSettings;
private final PreferenceDataStore mPluginEnabler;
private final String mPackageName;
private final ResolveInfo mSettingsInfo;
private final PreferenceDataStore mPluginEnabler;
private final List<ComponentName> mComponentNames;
PluginPreference(Context prefContext, ApplicationInfo info,
PluginPreference(Context prefContext, ResolveInfo pluginInfo,
PreferenceDataStore pluginEnabler, List<ComponentName> componentNames) {
super(prefContext);
PackageManager pm = prefContext.getPackageManager();
mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
.setPackage(info.packageName), 0) != null;
mPackageName = info.packageName;
mComponentNames = componentNames;
mPackageName = pluginInfo.serviceInfo.applicationInfo.packageName;
Intent settingsIntent = new Intent(ACTION_PLUGIN_SETTINGS).setPackage(mPackageName);
// If any Settings activity in app has category filters, set plugin action as category.
List<ResolveInfo> settingsInfos =
pm.queryIntentActivities(settingsIntent, GET_RESOLVED_FILTER);
if (pluginInfo.filter != null) {
for (ResolveInfo settingsInfo : settingsInfos) {
if (settingsInfo.filter != null && settingsInfo.filter.countCategories() > 0) {
settingsIntent.addCategory(pluginInfo.filter.getAction(0));
break;
}
}
}
mSettingsInfo = pm.resolveActivity(settingsIntent, 0);
mPluginEnabler = pluginEnabler;
setTitle(info.loadLabel(pm));
mComponentNames = componentNames;
setTitle(pluginInfo.loadLabel(pm));
setChecked(isPluginEnabled());
setWidgetLayoutResource(R.layout.switch_preference_with_settings);
}
@@ -396,17 +409,14 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
: View.GONE);
holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
: View.GONE);
boolean hasSettings = mSettingsInfo != null;
holder.findViewById(R.id.settings).setVisibility(hasSettings ? VISIBLE : GONE);
holder.findViewById(R.id.divider).setVisibility(hasSettings ? VISIBLE : GONE);
holder.findViewById(R.id.settings).setOnClickListener(v -> {
ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
new Intent(ACTION_PLUGIN_SETTINGS).setPackage(mPackageName), 0);
if (result != null) {
if (hasSettings) {
v.getContext().startActivity(new Intent().setComponent(
new ComponentName(result.activityInfo.packageName,
result.activityInfo.name)));
new ComponentName(mSettingsInfo.activityInfo.packageName,
mSettingsInfo.activityInfo.name)));
}
});
holder.itemView.setOnLongClickListener(v -> {