blob: 6844dee45a73bb5e8e2b6d44283309ee50ab59b1 [file] [log] [blame]
/*
* Copyright (C) 2018 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.car.carlauncher;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
/**
* The search result adapter that binds the filtered result to a list view.
*/
final class SearchResultAdapter
extends RecyclerView.Adapter<SearchResultAdapter.ViewHolder> implements Filterable {
private final Activity mContext;
private List<AppMetaData> mAllApps;
private List<AppMetaData> mSearchResults;
private AppSearchFilter filter;
private boolean mIsDistractionOptimizationRequired;
public SearchResultAdapter(Activity context) {
mContext = context;
mSearchResults = null;
}
public void setIsDistractionOptimizationRequired(boolean isDistractionOptimizationRequired) {
mIsDistractionOptimizationRequired = isDistractionOptimizationRequired;
notifyDataSetChanged();
}
public void setAllApps(List<AppMetaData> apps) {
mAllApps = apps;
notifyDataSetChanged();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private View mAppItem;
private ImageView mAppIconView;
private TextView mAppNameView;
public ViewHolder(View view) {
super(view);
mAppItem = view.findViewById(R.id.app_item);
mAppIconView = mAppItem.findViewById(R.id.app_icon);
mAppNameView = mAppItem.findViewById(R.id.app_name);
}
public void bind(AppMetaData app, View.OnClickListener listener) {
if (app == null) {
// Empty out the view
mAppIconView.setImageDrawable(null);
mAppNameView.setText(null);
mAppItem.setClickable(false);
mAppItem.setOnClickListener(null);
} else {
mAppIconView.setImageDrawable(app.getIcon());
mAppNameView.setText(app.getDisplayName());
mAppItem.setClickable(true);
mAppItem.setOnClickListener(listener);
}
}
}
/**
* This filter does a simple case insensitive text match based on the application
* display name. e.g. "gm" -> "gmail".
* It only matches apps starting with the search query. It does not do sub-string matching.
*/
private class AppSearchFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List filterList = new ArrayList();
for (int i = 0; i < mAllApps.size(); i++) {
AppMetaData app = mAllApps.get(i);
if (shouldShowApp(
app.getDisplayName(),
constraint.toString(),
app.getIsDistractionOptimized())) {
filterList.add(app);
}
}
Collections.sort(filterList, AppLauncherUtils.ALPHABETICAL_COMPARATOR);
results.count = filterList.size();
results.values = filterList;
} else {
results.count = 0;
results.values = null;
}
return results;
}
private boolean shouldShowApp(
String displayName, String constraint, boolean isDistractionOptimized) {
if (!mIsDistractionOptimizationRequired
|| (mIsDistractionOptimizationRequired && isDistractionOptimized)) {
Pattern pattern = Pattern.compile(
"^" + constraint + ".*$", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
return pattern.matcher(displayName).matches();
}
return false;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mSearchResults = (ArrayList) results.values;
notifyDataSetChanged();
}
}
@Override
public Filter getFilter() {
if (filter == null) {
filter = new AppSearchFilter();
}
return filter;
}
@NonNull
@Override
public SearchResultAdapter.ViewHolder onCreateViewHolder(
@NonNull ViewGroup parent, int viewType) {
View view = mContext.getLayoutInflater().inflate(R.layout.app_search_result_item, null);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SearchResultAdapter.ViewHolder holder, int position) {
// Get the data item for this position
AppMetaData app = mSearchResults.get(position);
holder.bind(app, v -> AppLauncherUtils.launchApp(mContext, app));
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
if (mSearchResults != null) {
return mSearchResults.size();
} else {
return 0;
}
}
void clearResults() {
mSearchResults.clear();
notifyDataSetChanged();
}
}