Unify sorting between all apps and widget tray
- selected locale names are shown before latin - case independent sorting - main app > enterprise app Future possible refactoring: - Move all the *ItemInfo data structures to model package - Rename the comparator based on NOT what data structure it supports but what functionality it supports (locale? case independent? main app > enterprise app?) b/21271658 b/20339403 Change-Id: I8a776467392e21d5014e85cd3f51931a3ef89724
This commit is contained in:
@@ -7,6 +7,7 @@ import android.util.Log;
|
||||
import com.android.launcher3.compat.AlphabeticIndexCompat;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.model.AppNameComparator;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
@@ -18,96 +19,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
||||
/**
|
||||
* A private class to manage access to an app name comparator.
|
||||
*/
|
||||
class AppNameComparator {
|
||||
private final UserManagerCompat mUserManager;
|
||||
private final Collator mCollator;
|
||||
private final Comparator<AppInfo> mAppInfoComparator;
|
||||
private final Comparator<String> mSectionNameComparator;
|
||||
private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
|
||||
|
||||
public AppNameComparator(Context context) {
|
||||
mCollator = Collator.getInstance();
|
||||
mUserManager = UserManagerCompat.getInstance(context);
|
||||
mAppInfoComparator = new Comparator<AppInfo>() {
|
||||
public final int compare(AppInfo a, AppInfo b) {
|
||||
// Order by the title in the current locale
|
||||
int result = compareTitles(a.title.toString(), b.title.toString());
|
||||
if (result == 0) {
|
||||
// If two apps have the same title, then order by the component name
|
||||
result = a.componentName.compareTo(b.componentName);
|
||||
if (result == 0) {
|
||||
// If the two apps are the same component, then prioritize by the order that
|
||||
// the app user was created (prioritizing the main user's apps)
|
||||
if (UserHandleCompat.myUserHandle().equals(a.user)) {
|
||||
return -1;
|
||||
} else {
|
||||
Long aUserSerial = getAndCacheUserSerial(a.user);
|
||||
Long bUserSerial = getAndCacheUserSerial(b.user);
|
||||
return aUserSerial.compareTo(bUserSerial);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
mSectionNameComparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return compareTitles(o1, o2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a locale-aware comparator that will alphabetically order a list of applications.
|
||||
*/
|
||||
public Comparator<AppInfo> getAppInfoComparator() {
|
||||
// Clear the user serial cache so that we get serials as needed in the comparator
|
||||
mUserSerialCache.clear();
|
||||
return mAppInfoComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a locale-aware comparator that will alphabetically order a list of section names.
|
||||
*/
|
||||
public Comparator<String> getSectionNameComparator() {
|
||||
return mSectionNameComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two titles with the same return value semantics as Comparator.
|
||||
*/
|
||||
private int compareTitles(String titleA, String titleB) {
|
||||
// Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
|
||||
boolean aStartsWithLetter = Character.isLetterOrDigit(titleA.codePointAt(0));
|
||||
boolean bStartsWithLetter = Character.isLetterOrDigit(titleB.codePointAt(0));
|
||||
if (aStartsWithLetter && !bStartsWithLetter) {
|
||||
return -1;
|
||||
} else if (!aStartsWithLetter && bStartsWithLetter) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Order by the title in the current locale
|
||||
return mCollator.compare(titleA, titleB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user serial for this user, using a cached serial if possible.
|
||||
*/
|
||||
private Long getAndCacheUserSerial(UserHandleCompat user) {
|
||||
Long userSerial = mUserSerialCache.get(user);
|
||||
if (userSerial == null) {
|
||||
userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
mUserSerialCache.put(user, userSerial);
|
||||
}
|
||||
return userSerial;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The alphabetically sorted list of applications.
|
||||
*/
|
||||
|
||||
@@ -66,7 +66,6 @@ import com.android.launcher3.util.Thunk;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -3665,39 +3664,6 @@ public class LauncherModel extends BroadcastReceiver
|
||||
return folderInfo;
|
||||
}
|
||||
|
||||
public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
|
||||
private final AppWidgetManagerCompat mManager;
|
||||
private final PackageManager mPackageManager;
|
||||
private final HashMap<Object, String> mLabelCache;
|
||||
private final Collator mCollator;
|
||||
|
||||
public WidgetAndShortcutNameComparator(Context context) {
|
||||
mManager = AppWidgetManagerCompat.getInstance(context);
|
||||
mPackageManager = context.getPackageManager();
|
||||
mLabelCache = new HashMap<Object, String>();
|
||||
mCollator = Collator.getInstance();
|
||||
}
|
||||
public final int compare(Object a, Object b) {
|
||||
String labelA, labelB;
|
||||
if (mLabelCache.containsKey(a)) {
|
||||
labelA = mLabelCache.get(a);
|
||||
} else {
|
||||
labelA = (a instanceof LauncherAppWidgetProviderInfo)
|
||||
? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a))
|
||||
: Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager));
|
||||
mLabelCache.put(a, labelA);
|
||||
}
|
||||
if (mLabelCache.containsKey(b)) {
|
||||
labelB = mLabelCache.get(b);
|
||||
} else {
|
||||
labelB = (b instanceof LauncherAppWidgetProviderInfo)
|
||||
? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b))
|
||||
: Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
|
||||
mLabelCache.put(b, labelB);
|
||||
}
|
||||
return mCollator.compare(labelA, labelB);
|
||||
}
|
||||
};
|
||||
|
||||
static boolean isValidProvider(AppWidgetProviderInfo provider) {
|
||||
return (provider != null) && (provider.provider != null)
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Class to manage access to an app name comparator.
|
||||
* <p>
|
||||
* Used to sort application name in all apps view and widget tray view.
|
||||
*/
|
||||
public class AppNameComparator {
|
||||
private final UserManagerCompat mUserManager;
|
||||
private final Collator mCollator;
|
||||
private final Comparator<ItemInfo> mAppInfoComparator;
|
||||
private final Comparator<String> mSectionNameComparator;
|
||||
private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
|
||||
|
||||
public AppNameComparator(Context context) {
|
||||
mCollator = Collator.getInstance();
|
||||
mUserManager = UserManagerCompat.getInstance(context);
|
||||
mAppInfoComparator = new Comparator<ItemInfo>() {
|
||||
|
||||
public final int compare(ItemInfo a, ItemInfo b) {
|
||||
// Order by the title in the current locale
|
||||
int result = compareTitles(a.title.toString(), b.title.toString());
|
||||
if (result == 0 && a instanceof AppInfo && b instanceof AppInfo) {
|
||||
AppInfo aAppInfo = (AppInfo) a;
|
||||
AppInfo bAppInfo = (AppInfo) b;
|
||||
// If two apps have the same title, then order by the component name
|
||||
result = aAppInfo.componentName.compareTo(bAppInfo.componentName);
|
||||
if (result == 0) {
|
||||
// If the two apps are the same component, then prioritize by the order that
|
||||
// the app user was created (prioritizing the main user's apps)
|
||||
if (UserHandleCompat.myUserHandle().equals(a.user)) {
|
||||
return -1;
|
||||
} else {
|
||||
Long aUserSerial = getAndCacheUserSerial(a.user);
|
||||
Long bUserSerial = getAndCacheUserSerial(b.user);
|
||||
return aUserSerial.compareTo(bUserSerial);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
mSectionNameComparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return compareTitles(o1, o2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a locale-aware comparator that will alphabetically order a list of applications.
|
||||
*/
|
||||
public Comparator<ItemInfo> getAppInfoComparator() {
|
||||
// Clear the user serial cache so that we get serials as needed in the comparator
|
||||
mUserSerialCache.clear();
|
||||
return mAppInfoComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a locale-aware comparator that will alphabetically order a list of section names.
|
||||
*/
|
||||
public Comparator<String> getSectionNameComparator() {
|
||||
return mSectionNameComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two titles with the same return value semantics as Comparator.
|
||||
*/
|
||||
private int compareTitles(String titleA, String titleB) {
|
||||
// Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
|
||||
boolean aStartsWithLetter = Character.isLetterOrDigit(titleA.codePointAt(0));
|
||||
boolean bStartsWithLetter = Character.isLetterOrDigit(titleB.codePointAt(0));
|
||||
if (aStartsWithLetter && !bStartsWithLetter) {
|
||||
return -1;
|
||||
} else if (!aStartsWithLetter && bStartsWithLetter) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Order by the title in the current locale
|
||||
return mCollator.compare(titleA, titleB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user serial for this user, using a cached serial if possible.
|
||||
*/
|
||||
private Long getAndCacheUserSerial(UserHandleCompat user) {
|
||||
Long userSerial = mUserSerialCache.get(user);
|
||||
if (userSerial == null) {
|
||||
userSerial = mUserManager.getSerialNumberForUser(user);
|
||||
mUserSerialCache.put(user, userSerial);
|
||||
}
|
||||
return userSerial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class WidgetsAndShortcutNameComparator implements Comparator<Object> {
|
||||
private final AppWidgetManagerCompat mManager;
|
||||
private final PackageManager mPackageManager;
|
||||
private final HashMap<Object, String> mLabelCache;
|
||||
private final Collator mCollator;
|
||||
|
||||
public WidgetsAndShortcutNameComparator(Context context) {
|
||||
mManager = AppWidgetManagerCompat.getInstance(context);
|
||||
mPackageManager = context.getPackageManager();
|
||||
mLabelCache = new HashMap<Object, String>();
|
||||
mCollator = Collator.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int compare(Object a, Object b) {
|
||||
String labelA, labelB;
|
||||
if (mLabelCache.containsKey(a)) {
|
||||
labelA = mLabelCache.get(a);
|
||||
} else {
|
||||
labelA = (a instanceof LauncherAppWidgetProviderInfo)
|
||||
? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a))
|
||||
: Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager));
|
||||
mLabelCache.put(a, labelA);
|
||||
}
|
||||
if (mLabelCache.containsKey(b)) {
|
||||
labelB = mLabelCache.get(b);
|
||||
} else {
|
||||
labelB = (b instanceof LauncherAppWidgetProviderInfo)
|
||||
? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b))
|
||||
: Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
|
||||
mLabelCache.put(b, labelB);
|
||||
}
|
||||
int result = mCollator.compare(labelA, labelB);
|
||||
if (result == 0 && a instanceof AppWidgetProviderInfo &&
|
||||
b instanceof AppWidgetProviderInfo) {
|
||||
AppWidgetProviderInfo aInfo = (AppWidgetProviderInfo) a;
|
||||
AppWidgetProviderInfo bInfo = (AppWidgetProviderInfo) b;
|
||||
|
||||
// prioritize main user's widgets against work profile widgets.
|
||||
if (aInfo.getProfile().equals(android.os.Process.myUserHandle())) {
|
||||
return -1;
|
||||
} else if (bInfo.getProfile().equals(android.os.Process.myUserHandle())) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -10,8 +10,9 @@ import android.util.Log;
|
||||
import com.android.launcher3.IconCache;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.LauncherModel.WidgetAndShortcutNameComparator;
|
||||
import com.android.launcher3.compat.UserHandleCompat;
|
||||
import com.android.launcher3.model.AppNameComparator;
|
||||
import com.android.launcher3.model.WidgetsAndShortcutNameComparator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -40,12 +41,14 @@ public class WidgetsModel {
|
||||
private RecyclerView.Adapter mAdapter;
|
||||
|
||||
private Comparator mWidgetAndShortcutNameComparator;
|
||||
private Comparator mAppNameComparator;
|
||||
|
||||
private IconCache mIconCache;
|
||||
|
||||
public WidgetsModel(Context context, RecyclerView.Adapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mWidgetAndShortcutNameComparator = new WidgetAndShortcutNameComparator(context);
|
||||
mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context);
|
||||
mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator();
|
||||
mIconCache = LauncherAppState.getInstance().getIconCache();
|
||||
}
|
||||
|
||||
@@ -108,7 +111,7 @@ public class WidgetsModel {
|
||||
}
|
||||
|
||||
// sort.
|
||||
sortPackageItemInfos();
|
||||
Collections.sort(mPackageItemInfos, mAppNameComparator);
|
||||
for (PackageItemInfo p: mPackageItemInfos) {
|
||||
Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);
|
||||
}
|
||||
@@ -116,13 +119,4 @@ public class WidgetsModel {
|
||||
// notify.
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void sortPackageItemInfos() {
|
||||
Collections.sort(mPackageItemInfos, new Comparator<PackageItemInfo>() {
|
||||
@Override
|
||||
public int compare(PackageItemInfo lhs, PackageItemInfo rhs) {
|
||||
return lhs.title.toString().compareTo(rhs.title.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user