summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/launcher3/Launcher.java11
-rw-r--r--src/com/android/launcher3/allapps/AllAppsContainerView.java68
-rw-r--r--src/com/android/launcher3/allapps/AlphabeticalAppsList.java95
-rw-r--r--src/com/android/launcher3/allapps/AppSearchManager.java59
-rw-r--r--src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java98
-rw-r--r--src/com/android/launcher3/model/AbstractUserComparator.java67
-rw-r--r--src/com/android/launcher3/model/AppNameComparator.java49
7 files changed, 357 insertions, 90 deletions
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 51f091613..ef34660df 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,6 +100,7 @@ import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AppSearchManager;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
@@ -583,6 +584,11 @@ public class Launcher extends Activity
}
}
}
+
+ @Override
+ public void setSearchManager(AppSearchManager manager) {
+ mAppsView.setSearchManager(manager);
+ }
});
mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() {
private boolean mImportanceStored = false;
@@ -1158,6 +1164,11 @@ public class Launcher extends Activity
* Called to dismiss all apps if it is showing.
*/
public void dismissAllApps();
+
+ /**
+ * Sets the search manager to be used for app search.
+ */
+ public void setSearchManager(AppSearchManager manager);
}
public interface LauncherSearchCallbacks {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index d81f97f24..c05f7c0b9 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -41,6 +41,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.TextView;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.BaseContainerView;
import com.android.launcher3.BubbleTextView;
@@ -54,15 +55,15 @@ import com.android.launcher3.Folder;
import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherTransitionable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AppSearchManager.AppSearchResultCallback;
import com.android.launcher3.util.Thunk;
+import java.util.ArrayList;
import java.util.List;
-import java.util.regex.Pattern;
/**
@@ -171,7 +172,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
AlphabeticalAppsList.AdapterChangedCallback, AllAppsGridAdapter.PredictionBarSpacerCallbacks,
View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
- ViewTreeObserver.OnPreDrawListener {
+ ViewTreeObserver.OnPreDrawListener, AppSearchResultCallback {
public static final boolean GRID_MERGE_SECTIONS = true;
@@ -183,8 +184,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private static final int FADE_OUT_DURATION = 100;
private static final int SEARCH_TRANSLATION_X_DP = 18;
- private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
-
@Thunk Launcher mLauncher;
@Thunk AlphabeticalAppsList mApps;
private LayoutInflater mLayoutInflater;
@@ -221,6 +220,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
private CheckLongPressHelper mPredictionIconCheckForLongPress;
private View mPredictionIconUnderTouch;
+ private AppSearchManager mSearchManager;
+
public AllAppsContainerView(Context context) {
this(context, null);
}
@@ -231,7 +232,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- LauncherAppState app = LauncherAppState.getInstance();
Resources res = context.getResources();
mLauncher = (Launcher) context;
@@ -258,6 +258,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mContentMarginStart = mAdapter.getContentMarginStart();
mApps.setAdapter(mAdapter);
+ mSearchManager = mApps.newSimpleAppSearchManager();
}
/**
@@ -281,6 +282,11 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mApps.addApps(apps);
}
+ public void setSearchManager(AppSearchManager searchManager) {
+ mSearchManager.cancel(true);
+ mSearchManager = searchManager;
+ }
+
/**
* Updates existing apps in the list
*/
@@ -664,45 +670,26 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
public void afterTextChanged(final Editable s) {
String queryText = s.toString();
if (queryText.isEmpty()) {
- mApps.setFilter(null);
+ mSearchManager.cancel(true);
+ mApps.setOrderedFilter(null);
} else {
String formatStr = getResources().getString(R.string.all_apps_no_search_results);
mAdapter.setEmptySearchText(String.format(formatStr, queryText));
- // Do an intersection of the words in the query and each title, and filter out all the
- // apps that don't match all of the words in the query.
- final String queryTextLower = queryText.toLowerCase();
- final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
- mApps.setFilter(new AlphabeticalAppsList.Filter() {
- @Override
- public boolean retainApp(AppInfo info, String sectionName) {
- if (sectionName.toLowerCase().contains(queryTextLower)) {
- return true;
- }
- String title = info.title.toString();
- String[] words = SPLIT_PATTERN.split(title.toLowerCase());
- for (int qi = 0; qi < queryWords.length; qi++) {
- boolean foundMatch = false;
- for (int i = 0; i < words.length; i++) {
- if (words[i].startsWith(queryWords[qi])) {
- foundMatch = true;
- break;
- }
- }
- if (!foundMatch) {
- // If there is a word in the query that does not match any words in this
- // title, so skip it.
- return false;
- }
- }
- return true;
- }
- });
+ mSearchManager.cancel(false);
+ mSearchManager.doSearch(queryText, this);
}
scrollToTop();
}
@Override
+ public void onSearchResult(ArrayList<ComponentName> apps) {
+ if (apps != null) {
+ mApps.setOrderedFilter(apps);
+ }
+ }
+
+ @Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (ALLOW_SINGLE_APP_LAUNCH && actionId == EditorInfo.IME_ACTION_DONE) {
// Skip the quick-launch if there isn't exactly one item
@@ -796,7 +783,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* recycler view.
*/
private boolean handleTouchEvent(MotionEvent ev) {
- LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = mLauncher.getDeviceProfile();
int x = (int) ev.getX();
int y = (int) ev.getY();
@@ -919,6 +905,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* Shows the search field.
*/
private void showSearchField() {
+ mSearchManager.connect();
+
// Show the search bar and focus the search
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
getContext().getResources().getDisplayMetrics());
@@ -949,6 +937,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
* Hides the search field.
*/
private void hideSearchField(boolean animated, final boolean returnFocusToRecyclerView) {
+ mSearchManager.cancel(true);
+
final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0;
final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
getContext().getResources().getDisplayMetrics());
@@ -966,7 +956,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
if (resetTextField) {
mSearchBarEditView.setText("");
}
- mApps.setFilter(null);
+ mApps.setOrderedFilter(null);
if (returnFocusToRecyclerView) {
mAppsRecyclerView.requestFocus();
}
@@ -983,7 +973,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
if (resetTextField) {
mSearchBarEditView.setText("");
}
- mApps.setFilter(null);
+ mApps.setOrderedFilter(null);
mSearchButtonView.setAlpha(1f);
mSearchButtonView.setTranslationX(0f);
if (returnFocusToRecyclerView) {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 13e18289a..0dc2d1e63 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -1,13 +1,31 @@
+/*
+ * Copyright (C) 2015 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.allapps;
import android.content.ComponentName;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.model.AbstractUserComparator;
import com.android.launcher3.model.AppNameComparator;
import java.nio.charset.CharsetEncoder;
@@ -115,13 +133,6 @@ public class AlphabeticalAppsList {
}
/**
- * A filter interface to limit the set of applications in the apps list.
- */
- public interface Filter {
- boolean retainApp(AppInfo info, String sectionName);
- }
-
- /**
* Callback to notify when the set of adapter items have changed.
*/
public interface AdapterChangedCallback {
@@ -198,7 +209,7 @@ public class AlphabeticalAppsList {
private Launcher mLauncher;
// The set of apps from the system not including predictions
- private List<AppInfo> mApps = new ArrayList<>();
+ private final List<AppInfo> mApps = new ArrayList<>();
// The set of filtered apps with the current filter
private List<AppInfo> mFilteredApps = new ArrayList<>();
// The current set of adapter items
@@ -211,9 +222,10 @@ public class AlphabeticalAppsList {
private List<ComponentName> mPredictedAppComponents = new ArrayList<>();
// The set of predicted apps resolved from the component names and the current set of apps
private List<AppInfo> mPredictedApps = new ArrayList<>();
+ // The of ordered component names as a result of a search query
+ private ArrayList<ComponentName> mSearchResults;
private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
private RecyclerView.Adapter mAdapter;
- private Filter mFilter;
private AlphabeticIndexCompat mIndexer;
private AppNameComparator mAppNameComparator;
private MergeAlgorithm mMergeAlgorithm;
@@ -235,6 +247,10 @@ public class AlphabeticalAppsList {
mAdapterChangedCallback = cb;
}
+ public SimpleAppSearchManagerImpl newSimpleAppSearchManager() {
+ return new SimpleAppSearchManagerImpl(mApps);
+ }
+
/**
* Sets the number of apps per row. Used only for AppsContainerView.SECTIONED_GRID_COALESCED.
*/
@@ -293,22 +309,22 @@ public class AlphabeticalAppsList {
* Returns whether there are is a filter set.
*/
public boolean hasFilter() {
- return (mFilter != null);
+ return (mSearchResults != null);
}
/**
* Returns whether there are no filtered results.
*/
public boolean hasNoFilteredResults() {
- return (mFilter != null) && mFilteredApps.isEmpty();
+ return (mSearchResults != null) && mFilteredApps.isEmpty();
}
/**
- * Sets the current filter for this list of apps.
+ * Sets the sorted list of filtered components.
*/
- public void setFilter(Filter f) {
- if (mFilter != f) {
- mFilter = f;
+ public void setOrderedFilter(ArrayList<ComponentName> f) {
+ if (mSearchResults != f) {
+ mSearchResults = f;
updateAdapterItems();
}
}
@@ -428,7 +444,9 @@ public class AlphabeticalAppsList {
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
allApps.addAll(entry.getValue());
}
- mApps = allApps;
+
+ mApps.clear();
+ mApps.addAll(allApps);
} else {
// Just compute the section headers for use below
for (AppInfo info : mApps) {
@@ -483,16 +501,12 @@ public class AlphabeticalAppsList {
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
// ordered set of sections
- int numApps = mApps.size();
+ List<AppInfo> apps = getFiltersAppInfos();
+ int numApps = apps.size();
for (int i = 0; i < numApps; i++) {
- AppInfo info = mApps.get(i);
+ AppInfo info = apps.get(i);
String sectionName = getAndUpdateCachedSectionName(info.title);
- // Check if we want to retain this app
- if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
- continue;
- }
-
// Create a new section if the section names do not match
if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
lastSectionName = sectionName;
@@ -533,6 +547,41 @@ public class AlphabeticalAppsList {
}
}
+ private List<AppInfo> getFiltersAppInfos() {
+ if (mSearchResults == null) {
+ return mApps;
+ }
+
+ int total = mSearchResults.size();
+ final HashMap<ComponentName, Integer> sortOrder = new HashMap<>(total);
+ for (int i = 0; i < total; i++) {
+ sortOrder.put(mSearchResults.get(i), i);
+ }
+
+ ArrayList<AppInfo> result = new ArrayList<>();
+ for (AppInfo info : mApps) {
+ if (sortOrder.containsKey(info.componentName)) {
+ result.add(info);
+ }
+ }
+
+ Collections.sort(result, new AbstractUserComparator<AppInfo>(
+ LauncherAppState.getInstance().getContext()) {
+
+ @Override
+ public int compare(AppInfo lhs, AppInfo rhs) {
+ Integer indexA = sortOrder.get(lhs.componentName);
+ int result = indexA.compareTo(sortOrder.get(rhs.componentName));
+ if (result == 0) {
+ return super.compare(lhs, rhs);
+ } else {
+ return result;
+ }
+ }
+ });
+ return result;
+ }
+
/**
* Merges multiple sections to reduce visual raggedness.
*/
diff --git a/src/com/android/launcher3/allapps/AppSearchManager.java b/src/com/android/launcher3/allapps/AppSearchManager.java
new file mode 100644
index 000000000..b6aa22341
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AppSearchManager.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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.allapps;
+
+import android.content.ComponentName;
+
+import java.util.ArrayList;
+
+/**
+ * Interface for handling app search.
+ */
+public interface AppSearchManager {
+
+ /**
+ * Called when the search is about to be used. This method is optional for making a query but
+ * calling this appropriately can improve the initial response time.
+ */
+ void connect();
+
+ /**
+ * Cancels all pending search requests.
+ *
+ * @param interruptActiveRequests if true, any active requests which are already executing will
+ * be invalidated, and the corresponding results will not be sent. The client should usually
+ * set this to true, before beginning a new search session.
+ */
+ void cancel(boolean interruptActiveRequests);
+
+ /**
+ * Performs a search
+ */
+ void doSearch(String query, AppSearchResultCallback callback);
+
+ /**
+ * Callback for getting search results.
+ */
+ public interface AppSearchResultCallback {
+
+ /**
+ * Called when the search is complete.
+ *
+ * @param apps sorted list of matching components or null if in case of failure.
+ */
+ void onSearchResult(ArrayList<ComponentName> apps);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java b/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java
new file mode 100644
index 000000000..e8a31b546
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SimpleAppSearchManagerImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 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.allapps;
+
+import android.content.ComponentName;
+import android.os.Handler;
+
+import com.android.launcher3.AppInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * An {@link AppSearchManager} which does label matching on the UI thread.
+ */
+public class SimpleAppSearchManagerImpl implements AppSearchManager {
+
+ private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
+
+ private final List<AppInfo> mApps;
+ private final Handler mResultHandler;
+
+ public SimpleAppSearchManagerImpl(List<AppInfo> apps) {
+ mApps = apps;
+ mResultHandler = new Handler();
+ }
+
+ @Override
+ public void connect() {
+ // No op
+ }
+
+ @Override
+ public void cancel(boolean interruptActiveRequests) {
+ if (interruptActiveRequests) {
+ mResultHandler.removeCallbacksAndMessages(null);
+ }
+ }
+
+ @Override
+ public void doSearch(String query, final AppSearchResultCallback callback) {
+ // Do an intersection of the words in the query and each title, and filter out all the
+ // apps that don't match all of the words in the query.
+ final String queryTextLower = query.toLowerCase();
+ final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
+ final ArrayList<ComponentName> result = new ArrayList<ComponentName>();
+ int total = mApps.size();
+
+ for (int i = 0; i < total; i++) {
+ AppInfo info = mApps.get(i);
+ if (!result.contains(info.componentName) && matches(info, queryWords)) {
+ result.add(info.componentName);
+ }
+ }
+ mResultHandler.post(new Runnable() {
+
+ @Override
+ public void run() {
+ callback.onSearchResult(result);
+ }
+ });
+ }
+
+ private boolean matches(AppInfo info, String[] queryWords) {
+ String title = info.title.toString();
+ String[] words = SPLIT_PATTERN.split(title.toLowerCase());
+ for (int qi = 0; qi < queryWords.length; qi++) {
+ boolean foundMatch = false;
+ for (int i = 0; i < words.length; i++) {
+ if (words[i].startsWith(queryWords[qi])) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (!foundMatch) {
+ // If there is a word in the query that does not match any words in this
+ // title, so skip it.
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/src/com/android/launcher3/model/AbstractUserComparator.java b/src/com/android/launcher3/model/AbstractUserComparator.java
new file mode 100644
index 000000000..cf47ce648
--- /dev/null
+++ b/src/com/android/launcher3/model/AbstractUserComparator.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 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.model;
+
+import android.content.Context;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * A comparator to arrange items based on user profiles.
+ */
+public abstract class AbstractUserComparator<T extends ItemInfo> implements Comparator<T> {
+
+ private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
+ private final UserManagerCompat mUserManager;
+ private final UserHandleCompat mMyUser;
+
+ public AbstractUserComparator(Context context) {
+ mUserManager = UserManagerCompat.getInstance(context);
+ mMyUser = UserHandleCompat.myUserHandle();
+ }
+
+ @Override
+ public int compare(T lhs, T rhs) {
+ if (mMyUser.equals(lhs.user)) {
+ return -1;
+ } else {
+ Long aUserSerial = getAndCacheUserSerial(lhs.user);
+ Long bUserSerial = getAndCacheUserSerial(rhs.user);
+ return aUserSerial.compareTo(bUserSerial);
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ public void clearUserCache() {
+ mUserSerialCache.clear();
+ }
+}
diff --git a/src/com/android/launcher3/model/AppNameComparator.java b/src/com/android/launcher3/model/AppNameComparator.java
index 706f7515d..cdac40ac0 100644
--- a/src/com/android/launcher3/model/AppNameComparator.java
+++ b/src/com/android/launcher3/model/AppNameComparator.java
@@ -1,14 +1,27 @@
+/*
+ * Copyright (C) 2015 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.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.
@@ -16,17 +29,15 @@ import java.util.HashMap;
* 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 AbstractUserComparator<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>() {
+ mAppInfoComparator = new AbstractUserComparator<ItemInfo>(context) {
+ @Override
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());
@@ -38,13 +49,7 @@ public class AppNameComparator {
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 super.compare(a, b);
}
}
return result;
@@ -63,7 +68,7 @@ public class AppNameComparator {
*/
public Comparator<ItemInfo> getAppInfoComparator() {
// Clear the user serial cache so that we get serials as needed in the comparator
- mUserSerialCache.clear();
+ mAppInfoComparator.clearUserCache();
return mAppInfoComparator;
}
@@ -90,16 +95,4 @@ public class AppNameComparator {
// 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;
- }
}