Change the load logic of FolderNameProvider
Work profile apps are suggested as "Work" folder name
Bug: 147359653
Bug: 147359733
Change-Id: Idb2438de9c71c85cfeca6a6b0e116174ea2f3b62
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index af219ba..f76ca50 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -26,6 +26,8 @@
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
@@ -89,6 +91,15 @@
runtimeStatusFlags = info.runtimeStatusFlags;
}
+ @VisibleForTesting
+ public AppInfo(ComponentName componentName, CharSequence title,
+ UserHandle user, Intent intent) {
+ this.componentName = componentName;
+ this.title = title;
+ this.user = user;
+ this.intent = intent;
+ }
+
@Override
protected String dumpProperties() {
return super.dumpProperties() + " componentName=" + componentName;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index e005320..63b0e1e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,12 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
-import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
-
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -68,10 +62,17 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
+import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
+import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
+
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
* LauncherModel object held in a static. Also provide APIs for updating the database state
@@ -127,6 +128,16 @@
}
/**
+ * Returns AppInfo with corresponding package name.
+ * TODO: move to enqueueModelTask
+ */
+ public Optional<AppInfo> getAppInfoByPackageName(String pkg) {
+ return mBgAllAppsList.data.stream()
+ .filter(info -> info.componentName.getPackageName().equals(pkg))
+ .findAny();
+ }
+
+ /**
* Adds the provided items to the workspace.
*/
public void addAndBindAddedWorkspaceItems(List<Pair<ItemInfo, Object>> itemList) {
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index 37aa815..e58d484 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -15,13 +15,23 @@
*/
package com.android.launcher3.folder;
-import android.content.ComponentName;
import android.content.Context;
+import android.os.Process;
+import android.text.TextUtils;
-import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
import com.android.launcher3.WorkspaceItemInfo;
import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Locates provider for the folder name.
@@ -29,39 +39,65 @@
public class FolderNameProvider {
/**
- * IME usually has up to 3 suggest slots. Adding one as in Launcher, there are folder
- * name edit box that we can also provide suggestion.
+ * IME usually has up to 3 suggest slots. In total, there are 4 suggest slots as the folder
+ * name edit box can also be used to provide suggestion.
*/
public static final int SUGGEST_MAX = 4;
- /**
- * Returns suggested folder name.
- */
public CharSequence getSuggestedFolderName(Context context,
- ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] suggestName) {
- // Currently only run the algorithm on initial folder creation.
- // For more than 2 items in the folder, the ranking algorithm for finding
- // candidate folder name should be rewritten.
- if (workspaceItemInfos.size() == 2) {
- ComponentName cmp1 = workspaceItemInfos.get(0).getTargetComponent();
- ComponentName cmp2 = workspaceItemInfos.get(1).getTargetComponent();
+ ArrayList<WorkspaceItemInfo> workspaceItemInfos, CharSequence[] candidates) {
- String pkgName0 = cmp1 == null ? "" : cmp1.getPackageName();
- String pkgName1 = cmp2 == null ? "" : cmp2.getPackageName();
- // If the two icons are from the same package,
- // then assign the main icon's name
- if (pkgName0.equals(pkgName1)) {
- WorkspaceItemInfo wInfo0 = workspaceItemInfos.get(0);
- WorkspaceItemInfo wInfo1 = workspaceItemInfos.get(1);
- if (workspaceItemInfos.get(0).itemType == Favorites.ITEM_TYPE_APPLICATION) {
- suggestName[0] = wInfo0.title;
- } else if (wInfo1.itemType == Favorites.ITEM_TYPE_APPLICATION) {
- suggestName[0] = wInfo1.title;
- }
- return suggestName[0];
- // two icons are all shortcuts. Don't assign title
+ CharSequence suggest;
+ // If all the icons are from work profile,
+ // Then, suggest "Work" as the folder name
+ List<WorkspaceItemInfo> distinctItemInfos = workspaceItemInfos.stream()
+ .filter(distinctByKey(p-> p.user))
+ .collect(Collectors.toList());
+
+ if (distinctItemInfos.size() == 1
+ && !distinctItemInfos.get(0).user.equals(Process.myUserHandle())) {
+ // Place it as last viable suggestion
+ setAsLastSuggestion(candidates,
+ context.getResources().getString(R.string.work_folder_name));
+ }
+
+ // If all the icons are from same package (e.g., main icon, shortcut, shortcut)
+ // Then, suggest the package's title as the folder name
+ distinctItemInfos = workspaceItemInfos.stream()
+ .filter(distinctByKey(p-> p.getTargetComponent() != null
+ ? p.getTargetComponent().getPackageName() : ""))
+ .collect(Collectors.toList());
+
+ if (distinctItemInfos.size() == 1) {
+ Optional<AppInfo> info = LauncherAppState.getInstance(context).getModel()
+ .getAppInfoByPackageName(distinctItemInfos.get(0).getTargetComponent()
+ .getPackageName());
+ // Place it as first viable suggestion and shift everything else
+ info.ifPresent(i -> setAsFirstSuggestion(candidates, i.title.toString()));
+ }
+ return candidates[0];
+ }
+
+ private void setAsFirstSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
+ for (int i = candidatesOut.length - 1; i > 0; i--) {
+ if (TextUtils.isEmpty(candidatesOut[i])) {
+ candidatesOut[i - 1] = candidatesOut[i];
+ }
+ candidatesOut[0] = candidate;
+ }
+ }
+
+ private void setAsLastSuggestion(CharSequence[] candidatesOut, CharSequence candidate) {
+ for (int i = 0; i < candidate.length(); i++) {
+ if (TextUtils.isEmpty(candidatesOut[i])) {
+ candidatesOut[i] = candidate;
}
}
- return suggestName[0];
+ }
+
+ // This method can be moved to some Utility class location.
+ private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
+ Map<Object, Boolean> map = new ConcurrentHashMap<>();
+ return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}