Adding fast scroller in app list
Change-Id: I9b5c2225a7acf6d7d83d7d7a7bb08a023a66183d
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 716dde6..7d33156 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -22,12 +22,15 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.icu.text.AlphabeticIndex;
import android.os.Bundle;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.PreferenceFrameLayout;
+import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.LocaleList;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -45,6 +48,7 @@
import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.ListView;
+import android.widget.SectionIndexer;
import android.widget.Spinner;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.AppHeader;
@@ -79,6 +83,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Locale;
/**
* Activity to pick an application that will be used to display installation information and
@@ -300,6 +305,7 @@
}
mListView.setAdapter(mApplications);
mListView.setRecyclerListener(mApplications);
+ mListView.setFastScrollEnabled(isFastScrollEnabled());
Utils.prepareCustomPreferencesList(container, mRootView, mListView, false);
}
@@ -372,6 +378,17 @@
}
}
+ private boolean isFastScrollEnabled() {
+ switch (mListType) {
+ case LIST_TYPE_MAIN:
+ case LIST_TYPE_NOTIFICATION:
+ case LIST_TYPE_STORAGE:
+ return mSortOrder == R.id.sort_order_alpha;
+ default:
+ return false;
+ }
+ }
+
@Override
protected int getMetricsCategory() {
switch (mListType) {
@@ -545,6 +562,7 @@
case R.id.sort_order_alpha:
case R.id.sort_order_size:
mSortOrder = menuId;
+ mListView.setFastScrollEnabled(isFastScrollEnabled());
if (mApplications != null) {
mApplications.rebuild(mSortOrder);
}
@@ -699,7 +717,9 @@
*/
static class ApplicationsAdapter extends BaseAdapter implements Filterable,
ApplicationsState.Callbacks, AppStateBaseBridge.Callback,
- AbsListView.RecyclerListener {
+ AbsListView.RecyclerListener, SectionIndexer {
+ private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0];
+
private final ApplicationsState mState;
private final ApplicationsState.Session mSession;
private final ManageApplications mManageApplications;
@@ -718,6 +738,10 @@
private boolean mHasReceivedLoadEntries;
private boolean mHasReceivedBridgeCallback;
+ private AlphabeticIndex.ImmutableIndex mIndex;
+ private SectionInfo[] mSections = EMPTY_SECTIONS;
+ private int[] mPositionToSectionIndex;
+
private Filter mFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
@@ -867,9 +891,49 @@
mBaseEntries = entries;
if (mBaseEntries != null) {
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
+
+ if (mManageApplications.mListView.isFastScrollEnabled()) {
+ // Rebuild sections
+ if (mIndex == null) {
+ LocaleList locales = mContext.getResources().getConfiguration().getLocales();
+ if (locales.size() == 0) {
+ locales = new LocaleList(Locale.ENGLISH);
+ }
+ AlphabeticIndex index = new AlphabeticIndex<>(locales.getPrimary());
+ int localeCount = locales.size();
+ for (int i = 1; i < localeCount; i++) {
+ index.addLabels(locales.get(i));
+ }
+ // Ensure we always have some base English locale buckets
+ index.addLabels(Locale.ENGLISH);
+ mIndex = index.buildImmutableIndex();
+ }
+
+ ArrayList<SectionInfo> sections = new ArrayList<>();
+ int lastSecId = -1;
+ int totalEntries = mEntries.size();
+ mPositionToSectionIndex = new int[totalEntries];
+
+ for (int pos = 0; pos < totalEntries; pos++) {
+ String label = mEntries.get(pos).label;
+ int secId = mIndex.getBucketIndex(TextUtils.isEmpty(label) ? "" : label);
+ if (secId != lastSecId) {
+ lastSecId = secId;
+ sections.add(new SectionInfo(mIndex.getBucket(secId).getLabel(), pos));
+ }
+ mPositionToSectionIndex[pos] = sections.size() - 1;
+ }
+ mSections = sections.toArray(EMPTY_SECTIONS);
+ } else {
+ mSections = EMPTY_SECTIONS;
+ mPositionToSectionIndex = null;
+ }
} else {
mEntries = null;
+ mSections = EMPTY_SECTIONS;
+ mPositionToSectionIndex = null;
}
+
notifyDataSetChanged();
if (mSession.getAllApps().size() != 0
@@ -1112,6 +1176,21 @@
return mContext.getString(R.string.domain_urls_summary_some, result.valueAt(0));
}
}
+
+ @Override
+ public Object[] getSections() {
+ return mSections;
+ }
+
+ @Override
+ public int getPositionForSection(int sectionIndex) {
+ return mSections[sectionIndex].position;
+ }
+
+ @Override
+ public int getSectionForPosition(int position) {
+ return mPositionToSectionIndex[position];
+ }
}
private static class SummaryProvider implements SummaryLoader.SummaryProvider,
@@ -1185,6 +1264,21 @@
}
}
+ private static class SectionInfo {
+ final String label;
+ final int position;
+
+ public SectionInfo(String label, int position) {
+ this.label = label;
+ this.position = position;
+ }
+
+ @Override
+ public String toString() {
+ return label;
+ }
+ }
+
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
= new SummaryLoader.SummaryProviderFactory() {
@Override