1 package com.android.launcher3.model; 2 3 import android.content.ComponentName; 4 import android.content.Context; 5 import android.content.pm.PackageManager; 6 import android.content.pm.ResolveInfo; 7 import android.util.Log; 8 9 import com.android.launcher3.LauncherAppWidgetProviderInfo; 10 import com.android.launcher3.Utilities; 11 import com.android.launcher3.compat.AppWidgetManagerCompat; 12 import com.android.launcher3.compat.UserHandleCompat; 13 import com.android.launcher3.util.ComponentKey; 14 15 import java.text.Collator; 16 import java.util.Comparator; 17 import java.util.HashMap; 18 19 public class WidgetsAndShortcutNameComparator implements Comparator<Object> { 20 private final AppWidgetManagerCompat mManager; 21 private final PackageManager mPackageManager; 22 private final HashMap<ComponentKey, String> mLabelCache; 23 private final Collator mCollator; 24 private final UserHandleCompat mMainHandle; 25 WidgetsAndShortcutNameComparator(Context context)26 public WidgetsAndShortcutNameComparator(Context context) { 27 mManager = AppWidgetManagerCompat.getInstance(context); 28 mPackageManager = context.getPackageManager(); 29 mLabelCache = new HashMap<>(); 30 mCollator = Collator.getInstance(); 31 mMainHandle = UserHandleCompat.myUserHandle(); 32 } 33 34 /** 35 * Resets any stored state. 36 */ reset()37 public void reset() { 38 mLabelCache.clear(); 39 } 40 41 @Override compare(Object objA, Object objB)42 public final int compare(Object objA, Object objB) { 43 ComponentKey keyA = getComponentKey(objA); 44 ComponentKey keyB = getComponentKey(objB); 45 46 // Independent of how the labels compare, if only one of the two widget info belongs to 47 // work profile, put that one in the back. 48 boolean aWorkProfile = !mMainHandle.equals(keyA.user); 49 boolean bWorkProfile = !mMainHandle.equals(keyB.user); 50 if (aWorkProfile && !bWorkProfile) { 51 return 1; 52 } 53 if (!aWorkProfile && bWorkProfile) { 54 return -1; 55 } 56 57 // Get the labels for comparison 58 String labelA = mLabelCache.get(keyA); 59 String labelB = mLabelCache.get(keyB); 60 if (labelA == null) { 61 labelA = getLabel(objA); 62 mLabelCache.put(keyA, labelA); 63 } 64 if (labelB == null) { 65 labelB = getLabel(objB); 66 mLabelCache.put(keyB, labelB); 67 } 68 return mCollator.compare(labelA, labelB); 69 } 70 71 /** 72 * @return a component key for the given widget or shortcut info. 73 */ getComponentKey(Object o)74 private ComponentKey getComponentKey(Object o) { 75 if (o instanceof LauncherAppWidgetProviderInfo) { 76 LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; 77 return new ComponentKey(widgetInfo.provider, mManager.getUser(widgetInfo)); 78 } else { 79 ResolveInfo shortcutInfo = (ResolveInfo) o; 80 ComponentName cn = new ComponentName(shortcutInfo.activityInfo.packageName, 81 shortcutInfo.activityInfo.name); 82 // Currently, there are no work profile shortcuts 83 return new ComponentKey(cn, UserHandleCompat.myUserHandle()); 84 } 85 } 86 87 /** 88 * @return the label for the given widget or shortcut info. This may be an expensive call. 89 */ getLabel(Object o)90 private String getLabel(Object o) { 91 if (o instanceof LauncherAppWidgetProviderInfo) { 92 LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; 93 return Utilities.trim(mManager.loadLabel(widgetInfo)); 94 } else { 95 ResolveInfo shortcutInfo = (ResolveInfo) o; 96 try { 97 return Utilities.trim(shortcutInfo.loadLabel(mPackageManager)); 98 } catch (Exception e) { 99 Log.e("ShortcutNameComparator", 100 "Failed to extract app display name from resolve info", e); 101 return ""; 102 } 103 } 104 } 105 }; 106