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