Cleaning up some app model code.
- Preventing extra sorting when adding/updating apps - Preventing extra logic when filtering apps - Fixing overlapping prediction bar when all predictions are removed - Fixing crash when retrieving section names for AppInfos whose titles have been updated, but updateApps has not yet been called. Change-Id: I1da468b0fd5c5cc404b6a5e6146a268fefeca267
This commit is contained in:
@@ -5,14 +5,10 @@ import android.content.Context;
|
|||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.android.launcher3.compat.AlphabeticIndexCompat;
|
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 com.android.launcher3.model.AppNameComparator;
|
||||||
|
|
||||||
import java.text.Collator;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -121,10 +117,10 @@ public class AlphabeticalAppsList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback to notify of changes to the filter.
|
* Callback to notify when the set of adapter items have changed.
|
||||||
*/
|
*/
|
||||||
public interface FilterChangedCallback {
|
public interface AdapterChangedCallback {
|
||||||
void onFilterChanged();
|
void onAdapterItemsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,12 +174,20 @@ public class AlphabeticalAppsList {
|
|||||||
private static final int MAX_NUM_MERGES_PHONE = 2;
|
private static final int MAX_NUM_MERGES_PHONE = 2;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
|
// The set of apps from the system not including predictions
|
||||||
private List<AppInfo> mApps = new ArrayList<>();
|
private List<AppInfo> mApps = new ArrayList<>();
|
||||||
|
// The set of filtered apps with the current filter
|
||||||
private List<AppInfo> mFilteredApps = new ArrayList<>();
|
private List<AppInfo> mFilteredApps = new ArrayList<>();
|
||||||
private List<AdapterItem> mSectionedFilteredApps = new ArrayList<>();
|
// The current set of adapter items
|
||||||
|
private List<AdapterItem> mAdapterItems = new ArrayList<>();
|
||||||
|
// The set of sections for the apps with the current filter
|
||||||
private List<SectionInfo> mSections = new ArrayList<>();
|
private List<SectionInfo> mSections = new ArrayList<>();
|
||||||
|
// The set of sections that we allow fast-scrolling to (includes non-merged sections)
|
||||||
private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
|
private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
|
||||||
|
// The set of predicted app component names
|
||||||
private List<ComponentName> mPredictedAppComponents = new ArrayList<>();
|
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<>();
|
private List<AppInfo> mPredictedApps = new ArrayList<>();
|
||||||
private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
|
private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
|
||||||
private RecyclerView.Adapter mAdapter;
|
private RecyclerView.Adapter mAdapter;
|
||||||
@@ -191,16 +195,16 @@ public class AlphabeticalAppsList {
|
|||||||
private AlphabeticIndexCompat mIndexer;
|
private AlphabeticIndexCompat mIndexer;
|
||||||
private AppNameComparator mAppNameComparator;
|
private AppNameComparator mAppNameComparator;
|
||||||
private MergeAlgorithm mMergeAlgorithm;
|
private MergeAlgorithm mMergeAlgorithm;
|
||||||
private FilterChangedCallback mFilterChangedCallback;
|
private AdapterChangedCallback mAdapterChangedCallback;
|
||||||
private int mNumAppsPerRow;
|
private int mNumAppsPerRow;
|
||||||
private int mNumPredictedAppsPerRow;
|
private int mNumPredictedAppsPerRow;
|
||||||
|
|
||||||
public AlphabeticalAppsList(Context context, FilterChangedCallback cb, int numAppsPerRow,
|
public AlphabeticalAppsList(Context context, AdapterChangedCallback auCb, int numAppsPerRow,
|
||||||
int numPredictedAppsPerRow) {
|
int numPredictedAppsPerRow) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mIndexer = new AlphabeticIndexCompat(context);
|
mIndexer = new AlphabeticIndexCompat(context);
|
||||||
mAppNameComparator = new AppNameComparator(context);
|
mAppNameComparator = new AppNameComparator(context);
|
||||||
mFilterChangedCallback = cb;
|
mAdapterChangedCallback = auCb;
|
||||||
setNumAppsPerRow(numAppsPerRow, numPredictedAppsPerRow);
|
setNumAppsPerRow(numAppsPerRow, numPredictedAppsPerRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +252,7 @@ public class AlphabeticalAppsList {
|
|||||||
* Returns the current filtered list of applications broken down into their sections.
|
* Returns the current filtered list of applications broken down into their sections.
|
||||||
*/
|
*/
|
||||||
public List<AdapterItem> getAdapterItems() {
|
public List<AdapterItem> getAdapterItems() {
|
||||||
return mSectionedFilteredApps;
|
return mAdapterItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -278,11 +282,7 @@ public class AlphabeticalAppsList {
|
|||||||
public void setFilter(Filter f) {
|
public void setFilter(Filter f) {
|
||||||
if (mFilter != f) {
|
if (mFilter != f) {
|
||||||
mFilter = f;
|
mFilter = f;
|
||||||
onAppsUpdated();
|
updateAdapterItems();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
if (mFilterChangedCallback != null){
|
|
||||||
mFilterChangedCallback.onFilterChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,6 @@ public class AlphabeticalAppsList {
|
|||||||
mPredictedAppComponents.clear();
|
mPredictedAppComponents.clear();
|
||||||
mPredictedAppComponents.addAll(apps);
|
mPredictedAppComponents.addAll(apps);
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,7 +310,6 @@ public class AlphabeticalAppsList {
|
|||||||
mApps.clear();
|
mApps.clear();
|
||||||
mApps.addAll(apps);
|
mApps.addAll(apps);
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,10 +318,9 @@ public class AlphabeticalAppsList {
|
|||||||
public void addApps(List<AppInfo> apps) {
|
public void addApps(List<AppInfo> apps) {
|
||||||
// We add it in place, in alphabetical order
|
// We add it in place, in alphabetical order
|
||||||
for (AppInfo info : apps) {
|
for (AppInfo info : apps) {
|
||||||
addApp(info);
|
mApps.add(info);
|
||||||
}
|
}
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,11 +332,10 @@ public class AlphabeticalAppsList {
|
|||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
mApps.set(index, info);
|
mApps.set(index, info);
|
||||||
} else {
|
} else {
|
||||||
addApp(info);
|
mApps.add(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -353,7 +349,6 @@ public class AlphabeticalAppsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAppsUpdated();
|
onAppsUpdated();
|
||||||
mAdapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,16 +367,6 @@ public class AlphabeticalAppsList {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation to actually add an app to the alphabetic list, but does not notify.
|
|
||||||
*/
|
|
||||||
private void addApp(AppInfo info) {
|
|
||||||
int index = Collections.binarySearch(mApps, info, mAppNameComparator.getAppInfoComparator());
|
|
||||||
if (index < 0) {
|
|
||||||
mApps.add(-(index + 1), info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates internals when the set of apps are updated.
|
* Updates internals when the set of apps are updated.
|
||||||
*/
|
*/
|
||||||
@@ -389,18 +374,62 @@ public class AlphabeticalAppsList {
|
|||||||
// Sort the list of apps
|
// Sort the list of apps
|
||||||
Collections.sort(mApps, mAppNameComparator.getAppInfoComparator());
|
Collections.sort(mApps, mAppNameComparator.getAppInfoComparator());
|
||||||
|
|
||||||
// Prepare to update the list of sections, filtered apps, etc.
|
// As a special case for some languages (currently only Simplified Chinese), we may need to
|
||||||
mFilteredApps.clear();
|
// coalesce sections
|
||||||
mSections.clear();
|
Locale curLocale = mContext.getResources().getConfiguration().locale;
|
||||||
mSectionedFilteredApps.clear();
|
TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
|
||||||
mFastScrollerSections.clear();
|
boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
|
||||||
|
if (localeRequiresSectionSorting) {
|
||||||
|
// Compute the section headers. We use a TreeMap with the section name comparator to
|
||||||
|
// ensure that the sections are ordered when we iterate over it later
|
||||||
|
sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
|
||||||
|
for (AppInfo info : mApps) {
|
||||||
|
// Add the section to the cache
|
||||||
|
String sectionName = getAndUpdateCachedSectionName(info.title);
|
||||||
|
|
||||||
|
// Add it to the mapping
|
||||||
|
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
|
||||||
|
if (sectionApps == null) {
|
||||||
|
sectionApps = new ArrayList<>();
|
||||||
|
sectionMap.put(sectionName, sectionApps);
|
||||||
|
}
|
||||||
|
sectionApps.add(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add each of the section apps to the list in order
|
||||||
|
List<AppInfo> allApps = new ArrayList<>(mApps.size());
|
||||||
|
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
|
||||||
|
allApps.addAll(entry.getValue());
|
||||||
|
}
|
||||||
|
mApps = allApps;
|
||||||
|
} else {
|
||||||
|
// Just compute the section headers for use below
|
||||||
|
for (AppInfo info : mApps) {
|
||||||
|
// Add the section to the cache
|
||||||
|
getAndUpdateCachedSectionName(info.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recompose the set of adapter items from the current set of apps
|
||||||
|
updateAdapterItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the set of filtered apps with the current filter. At this point, we expect
|
||||||
|
* mCachedSectionNames to have been calculated for the set of all apps in mApps.
|
||||||
|
*/
|
||||||
|
private void updateAdapterItems() {
|
||||||
SectionInfo lastSectionInfo = null;
|
SectionInfo lastSectionInfo = null;
|
||||||
String lastSectionName = null;
|
String lastSectionName = null;
|
||||||
FastScrollSectionInfo lastFastScrollerSectionInfo = null;
|
FastScrollSectionInfo lastFastScrollerSectionInfo = null;
|
||||||
int position = 0;
|
int position = 0;
|
||||||
int appIndex = 0;
|
int appIndex = 0;
|
||||||
List<AppInfo> allApps = new ArrayList<>();
|
|
||||||
|
|
||||||
|
// Prepare to update the list of sections, filtered apps, etc.
|
||||||
|
mFilteredApps.clear();
|
||||||
|
mFastScrollerSections.clear();
|
||||||
|
mAdapterItems.clear();
|
||||||
|
mSections.clear();
|
||||||
|
|
||||||
// Process the predicted app components
|
// Process the predicted app components
|
||||||
mPredictedApps.clear();
|
mPredictedApps.clear();
|
||||||
@@ -421,61 +450,16 @@ public class AlphabeticalAppsList {
|
|||||||
if (!mPredictedApps.isEmpty()) {
|
if (!mPredictedApps.isEmpty()) {
|
||||||
// Create a new spacer for the prediction bar
|
// Create a new spacer for the prediction bar
|
||||||
AdapterItem sectionItem = AdapterItem.asPredictionBarSpacer(position++);
|
AdapterItem sectionItem = AdapterItem.asPredictionBarSpacer(position++);
|
||||||
mSectionedFilteredApps.add(sectionItem);
|
mAdapterItems.add(sectionItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As a special case for some languages (currently only Simplified Chinese), we may need to
|
|
||||||
// coalesce sections
|
|
||||||
Locale curLocale = mContext.getResources().getConfiguration().locale;
|
|
||||||
TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
|
|
||||||
boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
|
|
||||||
if (localeRequiresSectionSorting) {
|
|
||||||
// Compute the section headers. We use a TreeMap with the section name comparator to
|
|
||||||
// ensure that the sections are ordered when we iterate over it later
|
|
||||||
sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
|
|
||||||
for (AppInfo info : mApps) {
|
|
||||||
// Add the section to the cache
|
|
||||||
String sectionName = mCachedSectionNames.get(info.title);
|
|
||||||
if (sectionName == null) {
|
|
||||||
sectionName = mIndexer.computeSectionName(info.title);
|
|
||||||
mCachedSectionNames.put(info.title, sectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add it to the mapping
|
|
||||||
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
|
|
||||||
if (sectionApps == null) {
|
|
||||||
sectionApps = new ArrayList<>();
|
|
||||||
sectionMap.put(sectionName, sectionApps);
|
|
||||||
}
|
|
||||||
sectionApps.add(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add it to the list
|
|
||||||
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
|
|
||||||
allApps.addAll(entry.getValue());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Just compute the section headers for use below
|
|
||||||
for (AppInfo info : mApps) {
|
|
||||||
// Add the section to the cache
|
|
||||||
String sectionName = mCachedSectionNames.get(info.title);
|
|
||||||
if (sectionName == null) {
|
|
||||||
sectionName = mIndexer.computeSectionName(info.title);
|
|
||||||
mCachedSectionNames.put(info.title, sectionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add it to the list
|
|
||||||
allApps.addAll(mApps);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
|
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
|
||||||
// ordered set of sections
|
// ordered set of sections
|
||||||
int numApps = allApps.size();
|
int numApps = mApps.size();
|
||||||
for (int i = 0; i < numApps; i++) {
|
for (int i = 0; i < numApps; i++) {
|
||||||
AppInfo info = allApps.get(i);
|
AppInfo info = mApps.get(i);
|
||||||
// The section name was computed above so this should be find
|
String sectionName = getAndUpdateCachedSectionName(info.title);
|
||||||
String sectionName = mCachedSectionNames.get(info.title);
|
|
||||||
|
|
||||||
// Check if we want to retain this app
|
// Check if we want to retain this app
|
||||||
if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
|
if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
|
||||||
@@ -494,7 +478,7 @@ public class AlphabeticalAppsList {
|
|||||||
// Create a new section item to break the flow of items in the list
|
// Create a new section item to break the flow of items in the list
|
||||||
if (!hasFilter()) {
|
if (!hasFilter()) {
|
||||||
AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
|
AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
|
||||||
mSectionedFilteredApps.add(sectionItem);
|
mAdapterItems.add(sectionItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,12 +489,21 @@ public class AlphabeticalAppsList {
|
|||||||
lastSectionInfo.firstAppItem = appItem;
|
lastSectionInfo.firstAppItem = appItem;
|
||||||
lastFastScrollerSectionInfo.appItem = appItem;
|
lastFastScrollerSectionInfo.appItem = appItem;
|
||||||
}
|
}
|
||||||
mSectionedFilteredApps.add(appItem);
|
mAdapterItems.add(appItem);
|
||||||
mFilteredApps.add(info);
|
mFilteredApps.add(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge multiple sections together as requested by the merge strategy for this device
|
// Merge multiple sections together as requested by the merge strategy for this device
|
||||||
mergeSections();
|
mergeSections();
|
||||||
|
|
||||||
|
// Refresh the recycler view
|
||||||
|
if (mAdapter != null) {
|
||||||
|
mAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAdapterChangedCallback != null) {
|
||||||
|
mAdapterChangedCallback.onAdapterItemsChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -531,20 +524,20 @@ public class AlphabeticalAppsList {
|
|||||||
SectionInfo nextSection = mSections.remove(i + 1);
|
SectionInfo nextSection = mSections.remove(i + 1);
|
||||||
|
|
||||||
// Remove the next section break
|
// Remove the next section break
|
||||||
mSectionedFilteredApps.remove(nextSection.sectionBreakItem);
|
mAdapterItems.remove(nextSection.sectionBreakItem);
|
||||||
int pos = mSectionedFilteredApps.indexOf(section.firstAppItem);
|
int pos = mAdapterItems.indexOf(section.firstAppItem);
|
||||||
// Point the section for these new apps to the merged section
|
// Point the section for these new apps to the merged section
|
||||||
int nextPos = pos + section.numApps;
|
int nextPos = pos + section.numApps;
|
||||||
for (int j = nextPos; j < (nextPos + nextSection.numApps); j++) {
|
for (int j = nextPos; j < (nextPos + nextSection.numApps); j++) {
|
||||||
AdapterItem item = mSectionedFilteredApps.get(j);
|
AdapterItem item = mAdapterItems.get(j);
|
||||||
item.sectionInfo = section;
|
item.sectionInfo = section;
|
||||||
item.sectionAppIndex += section.numApps;
|
item.sectionAppIndex += section.numApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the following adapter items of the removed section item
|
// Update the following adapter items of the removed section item
|
||||||
pos = mSectionedFilteredApps.indexOf(nextSection.firstAppItem);
|
pos = mAdapterItems.indexOf(nextSection.firstAppItem);
|
||||||
for (int j = pos; j < mSectionedFilteredApps.size(); j++) {
|
for (int j = pos; j < mAdapterItems.size(); j++) {
|
||||||
AdapterItem item = mSectionedFilteredApps.get(j);
|
AdapterItem item = mAdapterItems.get(j);
|
||||||
item.position--;
|
item.position--;
|
||||||
}
|
}
|
||||||
section.numApps += nextSection.numApps;
|
section.numApps += nextSection.numApps;
|
||||||
@@ -560,4 +553,17 @@ public class AlphabeticalAppsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cached section name for the given title, recomputing and updating the cache if
|
||||||
|
* the title has no cached section name.
|
||||||
|
*/
|
||||||
|
private String getAndUpdateCachedSectionName(CharSequence title) {
|
||||||
|
String sectionName = mCachedSectionNames.get(title);
|
||||||
|
if (sectionName == null) {
|
||||||
|
sectionName = mIndexer.computeSectionName(title);
|
||||||
|
mCachedSectionNames.put(title, sectionName);
|
||||||
|
}
|
||||||
|
return sectionName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ final class HeaderElevationControllerVL implements HeaderElevationController {
|
|||||||
*/
|
*/
|
||||||
public class AppsContainerView extends BaseContainerView implements DragSource, Insettable,
|
public class AppsContainerView extends BaseContainerView implements DragSource, Insettable,
|
||||||
TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
|
TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
|
||||||
AlphabeticalAppsList.FilterChangedCallback, AppsGridAdapter.PredictionBarSpacerCallbacks,
|
AlphabeticalAppsList.AdapterChangedCallback, AppsGridAdapter.PredictionBarSpacerCallbacks,
|
||||||
View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
|
View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
|
||||||
ViewTreeObserver.OnPreDrawListener {
|
ViewTreeObserver.OnPreDrawListener {
|
||||||
|
|
||||||
@@ -686,7 +686,7 @@ public class AppsContainerView extends BaseContainerView implements DragSource,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFilterChanged() {
|
public void onAdapterItemsChanged() {
|
||||||
updatePredictionBarVisibility();
|
updatePredictionBarVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user