Merge "[PS] Update PS tile icon." into main
diff --git a/Android.bp b/Android.bp
index c4ea48a..eed67f5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -339,6 +339,7 @@
name: "Launcher3Go",
static_libs: ["Launcher3GoLib"],
+ resource_dirs: [],
platform_apis: true,
min_sdk_version: "current",
@@ -374,6 +375,7 @@
name: "Launcher3QuickStepGo",
static_libs: ["Launcher3GoLib"],
+ resource_dirs: [],
platform_apis: true,
min_sdk_version: "current",
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/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index cceaf27..2fedb6f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -38,6 +38,8 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
+import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -1647,6 +1649,12 @@
int taskToLaunch = mRecentsView.getNextPage();
int runningTask = getLastAppearedTaskIndex();
boolean hasStartedNewTask = hasStartedNewTask();
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ "taskToLaunch=" + taskToLaunch);
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ "runningTask=" + runningTask);
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ "hasStartedNewTask=" + hasStartedNewTask);
if (target == NEW_TASK && taskToLaunch == runningTask
&& !hasStartedNewTask) {
// We are about to launch the current running task, so use LAST_TASK
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 879fccb..711882c 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -97,6 +97,13 @@
RecentTasksList.this.onRunningTaskVanished(taskInfo);
});
}
+
+ @Override
+ public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mMainThreadExecutor.execute(() -> {
+ RecentTasksList.this.onRunningTaskChanged(taskInfo);
+ });
+ }
});
// We may receive onRunningTaskAppeared events later for tasks which have already been
// included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
@@ -244,6 +251,20 @@
}
}
+ private void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ // Find the task from the list of running tasks, if it exists
+ for (ActivityManager.RunningTaskInfo existingTask : mRunningTasks) {
+ if (existingTask.taskId != taskInfo.taskId) continue;
+
+ mRunningTasks.remove(existingTask);
+ mRunningTasks.add(taskInfo);
+ if (mRunningTasksListener != null) {
+ mRunningTasksListener.onRunningTasksChanged();
+ }
+ return;
+ }
+ }
+
/**
* Loads and creates a list of all the recent tasks.
*/
@@ -390,4 +411,4 @@
return mRequestId == requestId && (!mKeysOnly || loadKeysOnly);
}
}
-}
\ No newline at end of file
+}
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/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index e4d8e92..5b16c0f 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -33,8 +33,6 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -204,9 +202,6 @@
mLauncher.getLaunchedAppState().switchToOverview();
}
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
//@NavigationModeSwitch
@Test
public void goToOverviewFromApp() {
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
index 45723b0..a16d35a 100644
--- a/res/drawable/ic_install_to_private.xml
+++ b/res/drawable/ic_install_to_private.xml
@@ -22,10 +22,16 @@
android:viewportHeight="24"
android:tint="?attr/materialColorOnSurface">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19,5V19H5V5H19ZM19,3H5C3.9,3 3,3.9 3,5V19C3,20.1 3.9,21 5,21H19C20.1,21 21,20.1 21,19V5C21,3.9 20.1,3 19,3Z" />
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12.93,12.27L13.5,15.5H10.5L11.07,12.27C10.43,11.94 10,11.27 10,10.5C10,9.4 10.9,8.5 12,8.5C13.1,8.5 14,9.4 14,10.5C14,11.27 13.57,11.94 12.93,12.27Z" />
+ <group>
+ <clip-path
+ android:pathData="M0,0h24v24h-24z"/>
+ <path
+ android:pathData="M12.001,1.999L4.001,4.999V11.089C4.001,16.139 7.411,20.849 12.001,21.999C16.591,20.849 20.001,16.139 20.001,11.089V4.999L12.001,1.999ZM18.001,11.089C18.001,15.089 15.451,18.789 12.001,19.919C8.551,18.789 6.001,15.099 6.001,11.089V6.389L12.001,4.139L18.001,6.389V11.089Z"
+ android:fillColor="@android:color/white"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M8.501,9.5C8.501,11.08 9.561,12.41 11.001,12.84V18H13.001V17H15.001V15H13.001V12.84C14.441,12.41 15.501,11.09 15.501,9.5C15.501,7.57 13.931,6 12.001,6C10.071,6 8.501,7.57 8.501,9.5ZM13.501,9.5C13.501,10.33 12.831,11 12.001,11C11.171,11 10.501,10.33 10.501,9.5C10.501,8.67 11.171,8 12.001,8C12.831,8 13.501,8.67 13.501,9.5Z"
+ android:fillColor="@android:color/white"
+ android:fillType="evenOdd"/>
+ </group>
</vector>
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/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index c255eb5..8026d4a 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -191,7 +191,6 @@
private float mBottomSheetAlpha = 1f;
private boolean mForceBottomSheetVisible;
private int mTabsProtectionAlpha;
- private float mTotalHeaderProtectionHeight;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
public ActivityAllAppsContainerView(Context context) {
@@ -778,7 +777,7 @@
protected void updateHeaderScroll(int scrolledOffset) {
float prog1 = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
int headerColor = getHeaderColor(prog1);
- int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
+ int tabsAlpha = mHeader.getPeripheralProtectionHeight(/* expectedHeight */ false) == 0 ? 0
: (int) (Utilities.boundToRange(
(scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
* 255);
@@ -1448,15 +1447,13 @@
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
- mTotalHeaderProtectionHeight = headerBottomWithScaleOnTablet;
}
} else {
canvas.drawRect(0, 0, canvas.getWidth(), headerBottomWithScaleOnPhone, mHeaderPaint);
- mTotalHeaderProtectionHeight = headerBottomWithScaleOnPhone;
}
// If tab exist (such as work profile), extend header with tab height
- final int tabsHeight = headerView.getPeripheralProtectionHeight();
+ final int tabsHeight = headerView.getPeripheralProtectionHeight(/* expectedHeight */ false);
if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
if (DEBUG_HEADER_PROTECTION) {
mHeaderPaint.setColor(Color.BLUE);
@@ -1482,16 +1479,19 @@
right,
tabBottomWithScale,
mHeaderPaint);
- mTotalHeaderProtectionHeight = tabBottomWithScale;
}
}
/**
- * The height of the header protection is dynamically calculated during the time of drawing the
- * header.
+ * The height of the header protection as if the user scrolled down the app list.
*/
float getHeaderProtectionHeight() {
- return mTotalHeaderProtectionHeight;
+ float headerBottom = getHeaderBottom() - getTranslationY();
+ if (mUsingTabs) {
+ return headerBottom + mHeader.getPeripheralProtectionHeight(/* expectedHeight */ true);
+ } else {
+ return headerBottom;
+ }
}
/**
@@ -1515,6 +1515,10 @@
return bottom + mHeader.getTop();
}
+ boolean isUsingTabs() {
+ return mUsingTabs;
+ }
+
/**
* Returns a view that denotes the visible part of all apps container view.
*/
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index a1f6ebe..92c589c 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;
@@ -466,9 +466,14 @@
}
/**
- * Returns visible height of FloatingHeaderView contents requiring header protection
+ * Returns visible height of FloatingHeaderView contents requiring header protection or the
+ * expected header protection height.
*/
- int getPeripheralProtectionHeight() {
+ int getPeripheralProtectionHeight(boolean expected) {
+ if (expected) {
+ return getTabLayout().getBottom() - getPaddingTop() + getPaddingBottom()
+ - mMaxTranslation;
+ }
// we only want to show protection when work tab is available and header is either
// collapsed or animating to/from collapsed state
if (mTabsHidden || mFloatingRowsCollapsed || !mHeaderCollapsed) {
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 1def8a3..fc186e8 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -495,9 +495,12 @@
if (rowToExpandToWithRespectToHeader == -1) {
rowToExpandToWithRespectToHeader = currentItem.rowIndex;
}
+ // If there are no tabs, decrease the row to scroll to by 1 since the header
+ // may be cut off slightly.
int rowToScrollTo =
(int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
- - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
+ - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight)
+ - (mAllApps.isUsingTabs() ? 0 : 1);
int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
// rowToScrollTo - 1 since the item to scroll to is 0 indexed.
if (currentRowDistance == rowToScrollTo - 1) {
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/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index af704a8..329f717 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -572,7 +572,7 @@
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
mContext.getDrawable(widgetSection.mSectionDrawable),
- new BaseIconFactory.IconOptions().setShrinkNonAdaptiveIcons(false));
+ new BaseIconFactory.IconOptions());
mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap);
infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user);
} catch (Exception e) {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index d702e51..d5f1e18 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -75,9 +75,11 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LogConfig;
+import java.io.File;
import java.io.InvalidObjectException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -125,38 +127,53 @@
if (Flags.enableNarrowGridRestore()) {
String oldPhoneFileName = idp.dbFile;
+ List<String> previousDbs = existingDbs();
removeOldDBs(context, oldPhoneFileName);
// The idp before this contains data about the old phone, after this it becomes the idp
// of the current phone.
idp.reset(context);
- trySettingPreviousGidAsCurrent(context, idp, oldPhoneFileName);
+ trySettingPreviousGidAsCurrent(context, idp, oldPhoneFileName, previousDbs);
} else {
idp.reinitializeAfterRestore(context);
}
}
+
/**
* Try setting the gird used in the previous phone to the new one. If the current device doesn't
* support the previous grid option it will not be set.
*/
private static void trySettingPreviousGidAsCurrent(Context context, InvariantDeviceProfile idp,
- String oldPhoneDbFileName) {
- InvariantDeviceProfile.GridOption gridOption = idp.getGridOptionFromFileName(context,
- oldPhoneDbFileName);
- if (gridOption != null) {
+ String oldPhoneDbFileName, List<String> previousDbs) {
+ InvariantDeviceProfile.GridOption oldPhoneGridOption = idp.getGridOptionFromFileName(
+ context, oldPhoneDbFileName);
+ // The grid option could be null if current phone doesn't support the previous db.
+ if (oldPhoneGridOption != null) {
+ /* If the user only used the default db on the previous phone and the new default db is
+ * bigger than or equal to the previous one, then keep the new default db */
+ if (previousDbs.size() == 1 && oldPhoneGridOption.numColumns <= idp.numColumns
+ && oldPhoneGridOption.numRows <= idp.numRows) {
+ /* Keep the user in default grid */
+ return;
+ }
/*
- * We do this because in some cases different devices have different names for grid
- * options, in one device the grid option "normal" can be 4x4 while in other it
- * could be "practical". Calling this changes the current device grid to the same
- * we had in the other phone, in the case the current phone doesn't support the grid
- * option we use the default and migrate the db to the default. Migration occurs on
- * {@code GridSizeMigrationUtil#migrateGridIfNeeded}
+ * Here we are setting the previous db as the current one.
*/
- idp.setCurrentGrid(context, gridOption.name);
+ idp.setCurrentGrid(context, oldPhoneGridOption.name);
}
}
/**
+ * Returns a list of paths of the existing launcher dbs.
+ */
+ private static List<String> existingDbs() {
+ // At this point idp.dbFile contains the name of the dbFile from the previous phone
+ return LauncherFiles.GRID_DB_FILES.stream()
+ .filter(dbName -> new File(dbName).exists())
+ .toList();
+ }
+
+ /**
* Only keep the last database used on the previous device.
*/
private static void removeOldDBs(Context context, String oldPhoneDbFileName) {
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;
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 351b921..9363ce8 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -290,6 +290,7 @@
doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ when(mAllApps.isUsingTabs()).thenReturn(true);
mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
null, privateProfileManager);
mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
@@ -311,6 +312,43 @@
}
@Test
+ public void scrollForViewToBeVisibleInContainer_withHeaderNoTabs() {
+ when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
+ .thenReturn(iteminfo -> iteminfo.componentName == null
+ || !iteminfo.componentName.getPackageName()
+ .equals(CAMERA_PACKAGE_NAME));
+ doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+ doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+ .addPrivateSpaceHeader(any());
+ doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+ doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
+ when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+ when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ when(mAllApps.isUsingTabs()).thenReturn(false);
+ mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+ null, privateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+
+ int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT) - 1;
+ int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+ // The number of adapterItems should be the private space apps + one main app + header.
+ assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+ mAlphabeticalAppsList.getAdapterItems().size());
+ assertEquals(position,
+ privateProfileManager.scrollForHeaderToBeVisibleInContainer(
+ new AllAppsRecyclerView(mContext),
+ mAlphabeticalAppsList.getAdapterItems(),
+ PS_HEADER_HEIGHT,
+ ALL_APPS_CELL_HEIGHT));
+ }
+
+ @Test
public void scrollForViewToBeVisibleInContainer_withHeaderAndLessAppRowSpace() {
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
@@ -325,6 +363,7 @@
doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+ when(mAllApps.isUsingTabs()).thenReturn(true);
when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
null, privateProfileManager);
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index df71ec0..b7933c8 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -39,6 +39,7 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.Test;
@@ -132,6 +133,7 @@
*/
@Test
@PlatinumTest(focusArea = "launcher")
+ @ScreenRecordRule.ScreenRecord // b/319501259
public void uninstallWorkspaceIcon() throws IOException {
Point[] gridPositions = TestUtil.getCornersAndCenterPositions(mLauncher);
StringBuilder sb = new StringBuilder();
@@ -162,12 +164,10 @@
mLauncher.getWorkspace().verifyWorkspaceAppIconIsGone(
DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
- if (!TestStabilityRule.isPresubmit()) { // b/315847371
- Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
- Map<String, Point> finalPositions =
- mLauncher.getWorkspace().getWorkspaceIconsPositions();
- assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
- }
+ Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
+ Map<String, Point> finalPositions =
+ mLauncher.getWorkspace().getWorkspaceIconsPositions();
+ assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
} finally {
TestUtil.uninstallDummyApp();
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 7109083..99e15ba 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -300,7 +300,8 @@
if (userManager != null) {
for (UserHandle userHandle : userManager.getUserProfiles()) {
if (!userHandle.isSystem()) {
- mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
+ mDevice.executeShellCommand(
+ "pm remove-user --wait " + userHandle.getIdentifier());
}
}
}
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index cccda88..e08d37c 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -114,7 +114,7 @@
mLauncher.runToState(
() -> {
try {
- mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
+ mDevice.executeShellCommand("pm remove-user --wait " + mProfileUserId);
} catch (IOException e) {
throw new RuntimeException(e);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index d176136..4fa93ef 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -347,6 +347,7 @@
*/
public Map<String, Point> getWorkspaceIconsPositions() {
final UiObject2 workspace = verifyActiveContainer();
+ mLauncher.waitForLauncherInitialized(); // b/319501259
List<UiObject2> workspaceIcons =
mLauncher.waitForObjectsInContainer(workspace, AppIcon.getAnyAppIconSelector());
return workspaceIcons.stream()