Using resource overrides for PluginManager instead of code-swap
Bug: 330920490
Test: Presubmit
Flag: None
Change-Id: Ib1cd50f95873928b9ce104e8e95d21f1dca9c6e3
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index c4ee11a..28cdb99 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -34,6 +34,7 @@
<string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
<string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
<string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
+ <string name="plugin_manager_wrapper_class" translatable="false">com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl</string>
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
<string name="assist_utils_class" translatable="false"></string>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
index 6b44ca7..e94fa61 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -16,8 +16,12 @@
package com.android.launcher3.uioverrides.flags
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
import android.os.Handler
import android.provider.DeviceConfig
+import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import android.text.Html
import android.view.inputmethod.EditorInfo
import androidx.preference.Preference
@@ -26,9 +30,12 @@
import androidx.preference.SwitchPreference
import com.android.launcher3.ExtendedEditText
import com.android.launcher3.R
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
+import com.android.launcher3.util.PluginManagerWrapper
import com.android.quickstep.util.DeviceConfigHelper
import com.android.quickstep.util.DeviceConfigHelper.Companion.NAMESPACE_LAUNCHER
import com.android.quickstep.util.DeviceConfigHelper.DebugInfo
+import com.android.systemui.shared.plugins.PluginEnabler
/** Helper class to generate UI for Device Config */
class DevOptionsUiHelper {
@@ -142,7 +149,92 @@
.getInt(this.key, DeviceConfig.getInt(NAMESPACE_LAUNCHER, this.key, this.valueInCode))
.toString()
+ /**
+ * Inflates the preferences for plugins
+ *
+ * A single pref is added for a plugin-group. A plugin-group is a collection of plugins in a
+ * single apk which have the same android:process tags defined. The apk should also hold the
+ * PLUGIN_PERMISSION. We collect all the plugin intents which Launcher listens for and fetch all
+ * corresponding plugins on the device. When a plugin-group is enabled/disabled we also need to
+ * notify the pluginManager manually since the broadcast-mechanism only works in sysui process
+ */
+ fun inflatePluginPrefs(parent: PreferenceGroup) {
+ val context = parent.context
+ val manager = PluginManagerWrapper.INSTANCE[context] as PluginManagerWrapperImpl
+ val pm = context.packageManager
+
+ val pluginPermissionApps =
+ pm.getPackagesHoldingPermissions(
+ arrayOf(PLUGIN_PERMISSION),
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ )
+ .map { it.packageName }
+
+ manager.pluginActions
+ .flatMap { action ->
+ pm.queryIntentServices(
+ Intent(action),
+ PackageManager.MATCH_DISABLED_COMPONENTS or
+ PackageManager.GET_RESOLVED_FILTER
+ )
+ .filter { pluginPermissionApps.contains(it.serviceInfo.packageName) }
+ }
+ .groupBy { "${it.serviceInfo.packageName}-${it.serviceInfo.processName}" }
+ .values
+ .forEach { infoList ->
+ val pluginInfo = infoList[0]!!
+ val pluginUri = Uri.fromParts("package", pluginInfo.serviceInfo.packageName, null)
+
+ object : SwitchPreference(context) {
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ holder.itemView.setOnLongClickListener {
+ context.startActivity(
+ Intent(ACTION_APPLICATION_DETAILS_SETTINGS, pluginUri)
+ )
+ true
+ }
+ }
+ }
+ .apply {
+ isPersistent = true
+ title = pluginInfo.loadLabel(pm)
+ isChecked =
+ infoList.all {
+ manager.pluginEnabler.isEnabled(it.serviceInfo.componentName)
+ }
+ summary =
+ infoList
+ .map { it.filter }
+ .filter { it?.countActions() ?: 0 > 0 }
+ .joinToString(prefix = "Plugins: ") {
+ it.getAction(0)
+ .replace("com.android.systemui.action.PLUGIN_", "")
+ .replace("com.android.launcher3.action.PLUGIN_", "")
+ }
+
+ setOnPreferenceChangeListener { _, newVal ->
+ val disabledState =
+ if (newVal as Boolean) PluginEnabler.ENABLED
+ else PluginEnabler.DISABLED_MANUALLY
+ infoList.forEach {
+ manager.pluginEnabler.setDisabled(
+ it.serviceInfo.componentName,
+ disabledState
+ )
+ }
+ manager.notifyChange(Intent(Intent.ACTION_PACKAGE_CHANGED, pluginUri))
+ true
+ }
+
+ parent.addPreference(this)
+ }
+ }
+ }
+
companion object {
const val TAG = "DeviceConfigUIHelper"
+
+ const val PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN"
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
index 3f818ac..ca8da08 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
@@ -15,13 +15,7 @@
*/
package com.android.launcher3.uioverrides.flags;
-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.settings.SettingsActivity.EXTRA_FRAGMENT_HIGHLIGHT_KEY;
-import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
@@ -29,18 +23,11 @@
import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN;
import static com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
-import android.util.ArrayMap;
-import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -52,20 +39,12 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
-import androidx.preference.PreferenceViewHolder;
-import androidx.preference.SwitchPreference;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
-import com.android.systemui.shared.plugins.PluginEnabler;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
+import com.android.systemui.shared.plugins.PluginPrefs;
/**
* Dev-build only UI allowing developers to toggle flag settings and plugins.
@@ -73,15 +52,9 @@
*/
public class DeveloperOptionsUI {
- private static final String ACTION_PLUGIN_SETTINGS =
- "com.android.systemui.action.PLUGIN_SETTINGS";
- private static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
-
private final PreferenceFragmentCompat mFragment;
private final PreferenceScreen mPreferenceScreen;
- private PreferenceCategory mPluginsCategory;
-
public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) {
mFragment = fragment;
mPreferenceScreen = fragment.getPreferenceScreen();
@@ -97,8 +70,10 @@
DevOptionsUiHelper uiHelper = new DevOptionsUiHelper();
uiHelper.inflateServerFlags(newCategory("Server flags"));
+ if (PluginPrefs.hasPlugins(getContext())) {
+ uiHelper.inflatePluginPrefs(newCategory("Plugins"));
+ }
- loadPluginPrefs();
maybeAddSandboxCategory();
addOnboardingPrefsCatergory();
}
@@ -160,65 +135,6 @@
return mFragment.requireContext();
}
- private void loadPluginPrefs() {
- if (mPluginsCategory != null) {
- mPreferenceScreen.removePreference(mPluginsCategory);
- }
- if (!PluginManagerWrapper.hasPlugins(getContext())) {
- mPluginsCategory = null;
- return;
- }
- mPluginsCategory = newCategory("Plugins");
-
- PluginManagerWrapper manager = PluginManagerWrapper.INSTANCE.get(getContext());
- Context prefContext = getContext();
- PackageManager pm = getContext().getPackageManager();
-
- Set<String> pluginActions = manager.getPluginActions();
-
- ArrayMap<Pair<String, String>, ArrayList<Pair<String, ResolveInfo>>> plugins =
- new ArrayMap<>();
-
- Set<String> pluginPermissionApps = pm.getPackagesHoldingPermissions(
- new String[]{PLUGIN_PERMISSION}, MATCH_DISABLED_COMPONENTS)
- .stream()
- .map(pi -> pi.packageName)
- .collect(Collectors.toSet());
-
- for (String action : pluginActions) {
- String name = toName(action);
- List<ResolveInfo> result = pm.queryIntentServices(
- new Intent(action), MATCH_DISABLED_COMPONENTS | GET_RESOLVED_FILTER);
- for (ResolveInfo info : result) {
- String packageName = info.serviceInfo.packageName;
- if (!pluginPermissionApps.contains(packageName)) {
- continue;
- }
-
- Pair<String, String> key = Pair.create(packageName, info.serviceInfo.processName);
- if (!plugins.containsKey(key)) {
- plugins.put(key, new ArrayList<>());
- }
- plugins.get(key).add(Pair.create(name, info));
- }
- }
-
- PluginEnabler enabler = manager.getPluginEnabler();
- plugins.forEach((key, si) -> {
- String packageName = key.first;
- List<ComponentName> componentNames = si.stream()
- .map(p -> new ComponentName(packageName, p.second.serviceInfo.name))
- .collect(Collectors.toList());
- if (!componentNames.isEmpty()) {
- SwitchPreference pref = new PluginPreference(
- prefContext, si.get(0).second, enabler, componentNames);
- pref.setSummary("Plugins: "
- + si.stream().map(p -> p.first).collect(Collectors.joining(", ")));
- mPluginsCategory.addPreference(pref);
- }
- });
- }
-
private void maybeAddSandboxCategory() {
Context context = getContext();
if (context == null) {
@@ -321,102 +237,4 @@
});
return onboardingPref;
}
-
- private String toName(String action) {
- String str = action.replace("com.android.systemui.action.PLUGIN_", "")
- .replace("com.android.launcher3.action.PLUGIN_", "");
-
- StringBuilder b = new StringBuilder();
- for (String s : str.split("_")) {
- if (b.length() != 0) {
- b.append(' ');
- }
- b.append(s.substring(0, 1));
- b.append(s.substring(1).toLowerCase());
- }
- return b.toString();
- }
-
- private static class PluginPreference extends SwitchPreference {
- private final String mPackageName;
- private final ResolveInfo mSettingsInfo;
- private final PluginEnabler mPluginEnabler;
- private final List<ComponentName> mComponentNames;
-
- PluginPreference(Context prefContext, ResolveInfo pluginInfo,
- PluginEnabler pluginEnabler, List<ComponentName> componentNames) {
- super(prefContext);
- PackageManager pm = prefContext.getPackageManager();
- 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;
- mComponentNames = componentNames;
- setTitle(pluginInfo.loadLabel(pm));
- setChecked(isPluginEnabled());
- setWidgetLayoutResource(R.layout.switch_preference_with_settings);
- }
-
- private boolean isPluginEnabled() {
- for (ComponentName componentName : mComponentNames) {
- if (!mPluginEnabler.isEnabled(componentName)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- protected boolean persistBoolean(boolean isEnabled) {
- boolean shouldSendBroadcast = false;
- for (ComponentName componentName : mComponentNames) {
- if (mPluginEnabler.isEnabled(componentName) != isEnabled) {
- mPluginEnabler.setDisabled(componentName,
- isEnabled ? PluginEnabler.ENABLED : PluginEnabler.DISABLED_MANUALLY);
- shouldSendBroadcast = true;
- }
- }
- if (shouldSendBroadcast) {
- final String pkg = mPackageName;
- final Intent intent = new Intent(PLUGIN_CHANGED,
- pkg != null ? Uri.fromParts("package", pkg, null) : null);
- getContext().sendBroadcast(intent);
- }
- setChecked(isEnabled);
- return true;
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
- 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 -> {
- if (hasSettings) {
- v.getContext().startActivity(new Intent().setComponent(
- new ComponentName(mSettingsInfo.activityInfo.packageName,
- mSettingsInfo.activityInfo.name)));
- }
- });
- holder.itemView.setOnLongClickListener(v -> {
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- intent.setData(Uri.fromParts("package", mPackageName, null));
- getContext().startActivity(intent);
- return true;
- });
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
similarity index 74%
rename from quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
rename to quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
index a09d0a1..74572c4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
@@ -1,15 +1,17 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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
+ * 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.
+ * 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.launcher3.uioverrides.plugins;
@@ -24,11 +26,10 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginActionManager;
import com.android.systemui.shared.plugins.PluginInstance;
import com.android.systemui.shared.plugins.PluginManagerImpl;
@@ -41,35 +42,30 @@
import java.util.List;
import java.util.Set;
-public class PluginManagerWrapper {
-
- public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
- new MainThreadInitializedObject<>(PluginManagerWrapper::new);
-
- public static final String PLUGIN_CHANGED = PluginManager.PLUGIN_CHANGED;
+public class PluginManagerWrapperImpl extends PluginManagerWrapper {
private static final UncaughtExceptionPreHandlerManager UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER =
new UncaughtExceptionPreHandlerManager();
private final Context mContext;
- private final PluginManager mPluginManager;
+ private final PluginManagerImpl mPluginManager;
private final PluginEnablerImpl mPluginEnabler;
- private PluginManagerWrapper(Context c) {
+ public PluginManagerWrapperImpl(Context c) {
mContext = c;
mPluginEnabler = new PluginEnablerImpl(c);
List<String> privilegedPlugins = Collections.emptyList();
PluginInstance.Factory instanceFactory = new PluginInstance.Factory(
getClass().getClassLoader(), new PluginInstance.InstanceFactory<>(),
new PluginInstance.VersionCheckerImpl(), privilegedPlugins,
- Utilities.IS_DEBUG_DEVICE);
+ BuildConfig.IS_DEBUG_DEVICE);
PluginActionManager.Factory instanceManagerFactory = new PluginActionManager.Factory(
c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR,
c.getSystemService(NotificationManager.class), mPluginEnabler,
privilegedPlugins, instanceFactory);
mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
- Utilities.IS_DEBUG_DEVICE,
+ BuildConfig.IS_DEBUG_DEVICE,
UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER, mPluginEnabler,
new PluginPrefs(c), privilegedPlugins);
}
@@ -78,18 +74,13 @@
return mPluginEnabler;
}
- /** */
- public <T extends Plugin> void addPluginListener(
- PluginListener<T> listener, Class<T> pluginClass) {
- addPluginListener(listener, pluginClass, false);
- }
-
- /** */
+ @Override
public <T extends Plugin> void addPluginListener(
PluginListener<T> listener, Class<T> pluginClass, boolean allowMultiple) {
mPluginManager.addPluginListener(listener, pluginClass, allowMultiple);
}
+ @Override
public void removePluginListener(PluginListener<? extends Plugin> listener) {
mPluginManager.removePluginListener(listener);
}
@@ -98,10 +89,12 @@
return new PluginPrefs(mContext).getPluginList();
}
- public static boolean hasPlugins(Context context) {
- return PluginPrefs.hasPlugins(context);
+ /** Notifies that a plugin state has changed */
+ public void notifyChange(Intent intent) {
+ mPluginManager.onReceive(mContext, intent);
}
+ @Override
public void dump(PrintWriter pw) {
final List<ComponentName> enabledPlugins = new ArrayList<>();
final List<ComponentName> disabledPlugins = new ArrayList<>();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7035d6e..6635ee4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -95,9 +95,9 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.LockedUserState;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
diff --git a/res/layout/switch_preference_with_settings.xml b/res/layout/switch_preference_with_settings.xml
deleted file mode 100644
index cd51833..0000000
--- a/res/layout/switch_preference_with_settings.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical">
-
- <ImageView
- android:id="@+id/settings"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_setting"
- android:forceDarkAllowed="true"
- android:padding="12dp"
- android:background="?android:attr/selectableItemBackgroundBorderless" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="1dp"
- android:layout_height="30dp"
- android:layout_marginEnd="8dp"
- android:background="?android:attr/listDivider" />
-
- <!-- Note: seems we need focusable="false" and clickable="false" when moving to androidx -->
- <Switch
- android:id="@android:id/switch_widget"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@null" />
-</LinearLayout>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index f820e76..393a197 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -84,7 +84,7 @@
<string name="wallpaper_picker_package" translatable="false"></string>
<string name="local_colors_extraction_class" translatable="false"></string>
<string name="search_session_manager_class" translatable="false"></string>
-
+ <string name="plugin_manager_wrapper_class" translatable="false"></string>
<!-- Scalable Grid configuration -->
<!-- This is a float because it is converted to dp later in DeviceProfile -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d2d5ba9..c91d4d0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -222,7 +222,6 @@
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.ActivityResultInfo;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.BackPressHandler;
@@ -235,6 +234,7 @@
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
@@ -576,8 +576,8 @@
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
mOverlayManager = getDefaultOverlay();
- PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this,
- LauncherOverlayPlugin.class, false /* allowedMultiple */);
+ PluginManagerWrapper.INSTANCE.get(this)
+ .addPluginListener(this, LauncherOverlayPlugin.class);
mRotationHelper.initialize();
TraceHelper.INSTANCE.endSection();
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index a1f6ebe..e25a2eb 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -34,7 +34,7 @@
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.views.ActivityContext;
import com.android.systemui.plugins.AllAppsRow;
import com.android.systemui.plugins.AllAppsRow.OnHeightUpdatedListener;
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 6b3bb51..0e4b48e 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -90,12 +90,12 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.ActivityContext;
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index e6ee186..1008ebb 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -22,7 +22,6 @@
import androidx.annotation.FractionRes;
import androidx.annotation.IntegerRes;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ResourceProvider;
diff --git a/src/com/android/launcher3/util/PluginManagerWrapper.java b/src/com/android/launcher3/util/PluginManagerWrapper.java
new file mode 100644
index 0000000..b27aa12
--- /dev/null
+++ b/src/com/android/launcher3/util/PluginManagerWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.launcher3.util;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+
+import java.io.PrintWriter;
+
+public class PluginManagerWrapper implements ResourceBasedOverride, SafeCloseable {
+
+ public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
+ forOverride(PluginManagerWrapper.class, R.string.plugin_manager_wrapper_class);
+
+ public <T extends Plugin> void addPluginListener(
+ PluginListener<T> listener, Class<T> pluginClass) {
+ addPluginListener(listener, pluginClass, false);
+ }
+
+ public <T extends Plugin> void addPluginListener(
+ PluginListener<T> listener, Class<T> pluginClass, boolean allowMultiple) {
+ }
+
+ public void removePluginListener(PluginListener<? extends Plugin> listener) { }
+
+ @Override
+ public void close() { }
+
+ public void dump(PrintWriter pw) { }
+}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 2fdf354..05fe8e3 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -32,9 +32,9 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/src_no_quickstep/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
deleted file mode 100644
index e1a35c9..0000000
--- a/src_no_quickstep/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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.launcher3.uioverrides.plugins;
-
-import android.content.ComponentName;
-import android.content.Context;
-
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginListener;
-
-import java.util.Collections;
-import java.util.Set;
-
-import androidx.preference.PreferenceDataStore;
-
-public class PluginManagerWrapper {
-
- public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
- new MainThreadInitializedObject<>(PluginManagerWrapper::new);
-
- private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
- public static final String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED";
-
- private PluginManagerWrapper(Context c) {
- }
-
- public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass) {
- }
-
- public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass,
- boolean allowMultiple) {
- }
-
- public void removePluginListener(PluginListener<? extends Plugin> listener) { }
-
- public Set<String> getPluginActions() {
- return Collections.emptySet();
- }
-
- public PreferenceDataStore getPluginEnabler() {
- return new PreferenceDataStore() { };
- }
-
- public static String pluginEnabledKey(ComponentName cn) {
- return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
- }
-
- public static boolean hasPlugins(Context context) {
- return false;
- }
-}
diff --git a/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java b/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java
new file mode 100644
index 0000000..e327648
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this plugin to proxy network requests
+ */
+@ProvidesInterface(action = NetworkFetcherPlugin.ACTION, version = NetworkFetcherPlugin.VERSION)
+public interface NetworkFetcherPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_NETWORK_FETCHER_ACTIONS";
+ int VERSION = 1;
+
+ /** Fetches the provided user and return all byte contents */
+ byte[] fetchUrl(String url) throws Exception;
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index e806d1d..0009a4e 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -60,7 +60,6 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.testing.TestInformationProvider;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.widget.custom.CustomWidgetManager;