diff --git a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/MainActivity.java b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/MainActivity.java index 408e01d..0501c58 100644 --- a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/MainActivity.java +++ b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/MainActivity.java @@ -19,11 +19,16 @@ package org.eu.exodus_privacy.exodusprivacy; import android.support.v4.app.FragmentManager; +import android.app.SearchManager; +import android.content.Context; import android.databinding.DataBindingUtil; import android.support.design.widget.Snackbar; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.support.v7.widget.SearchView; +import android.view.Menu; +import android.view.MenuInflater; import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter; import org.eu.exodus_privacy.exodusprivacy.databinding.MainBinding; @@ -94,4 +99,30 @@ public class MainActivity extends AppCompatActivity { else getSupportFragmentManager().popBackStack(); } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); + SearchView searchView = (SearchView) menu.findItem(R.id.action_filter).getActionView(); + assert searchManager != null; + searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); + searchView.setIconifiedByDefault(false); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + appList.filter(query); + return true; + } + + @Override + public boolean onQueryTextChange(String newText) { + appList.filter(newText); + return true; + } + }); + return true; + } } diff --git a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/adapters/ApplicationListAdapter.java b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/adapters/ApplicationListAdapter.java index 946dbe9..6655aef 100644 --- a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/adapters/ApplicationListAdapter.java +++ b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/adapters/ApplicationListAdapter.java @@ -22,32 +22,33 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.databinding.DataBindingUtil; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - import org.eu.exodus_privacy.exodusprivacy.R; import org.eu.exodus_privacy.exodusprivacy.databinding.AppItemBinding; import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager; import org.eu.exodus_privacy.exodusprivacy.objects.Report; import org.eu.exodus_privacy.exodusprivacy.objects.Tracker; - import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; -public class ApplicationListAdapter extends android.support.v7.widget.RecyclerView.Adapter{ +public class ApplicationListAdapter extends RecyclerView.Adapter { private List packages; private PackageManager packageManager; private OnAppClickListener onAppClickListener; private static final String gStore = "com.android.vending"; + private String filter = ""; + private final int HIDDEN_APP = 0; + private final int DISPLAYED_APP = 1; + private Comparator alphaPackageComparator = new Comparator() { @Override @@ -66,13 +67,13 @@ public class ApplicationListAdapter extends android.support.v7.widget.RecyclerVi private void setInstalledPackages(List installedPackages) { packages = installedPackages; applyStoreFilter(); - Collections.sort(packages,alphaPackageComparator); + Collections.sort(packages, alphaPackageComparator); notifyDataSetChanged(); } private void applyStoreFilter() { List toRemove = new ArrayList<>(); - for(PackageInfo pkg : packages) { + for (PackageInfo pkg : packages) { if (!gStore.equals(packageManager.getInstallerPackageName(pkg.packageName))) { toRemove.add(pkg); } @@ -81,22 +82,40 @@ public class ApplicationListAdapter extends android.support.v7.widget.RecyclerVi } @Override - public ApplicationListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - AppItemBinding appItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.app_item,parent,false); - return new ApplicationListViewHolder(appItemBinding); + public int getItemViewType(int position){ + return (Pattern.compile(Pattern.quote(filter.trim()), Pattern.CASE_INSENSITIVE).matcher(packageManager.getApplicationLabel(packages.get(position).applicationInfo)).find())?DISPLAYED_APP:HIDDEN_APP; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if( viewType == HIDDEN_APP) + return new ApplicationEmptyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.app_item_empty, parent, false)); + else + return new ApplicationListViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.app_item, parent, false)); + } @Override - public void onBindViewHolder(ApplicationListViewHolder holder, int position) { - holder.setData(packages.get(position)); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onAppClickListener.onAppClick(holder.packageInfo); - } - }); + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + if( viewHolder.getItemViewType() == DISPLAYED_APP) { + final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder; + holder.setData(packages.get(position)); + //noinspection Convert2Lambda + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onAppClickListener.onAppClick(holder.packageInfo); + } + }); + }else { + //noinspection unused + final ApplicationEmptyViewHolder holder = (ApplicationEmptyViewHolder) viewHolder; + //If something should be done for app that are hidden, it's here + } } + @Override public int getItemCount() { return packages.size(); @@ -110,6 +129,13 @@ public class ApplicationListAdapter extends android.support.v7.widget.RecyclerVi } } + class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{ + ApplicationEmptyViewHolder(View itemView) { + super(itemView); + } + } + + class ApplicationListViewHolder extends RecyclerView.ViewHolder { PackageInfo packageInfo; @@ -168,4 +194,10 @@ public class ApplicationListAdapter extends android.support.v7.widget.RecyclerVi public interface OnAppClickListener { void onAppClick(PackageInfo packageInfo); } + + + public void filter(String text) { + filter = text; + notifyDataSetChanged(); + } } diff --git a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/fragments/AppListFragment.java b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/fragments/AppListFragment.java index 6ae6eb9..7780ab4 100644 --- a/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/fragments/AppListFragment.java +++ b/app/src/main/java/org/eu/exodus_privacy/exodusprivacy/fragments/AppListFragment.java @@ -48,6 +48,7 @@ public class AppListFragment extends Fragment { private ApplicationListAdapter.OnAppClickListener onAppClickListener; private boolean startupRefresh; private ApplistBinding applistBinding; + private ApplicationListAdapter adapter; public static AppListFragment newInstance(NetworkListener networkListener, ApplicationListAdapter.OnAppClickListener appClickListener) { AppListFragment fragment = new AppListFragment(); @@ -86,7 +87,7 @@ public class AppListFragment extends Fragment { } applistBinding.noPackageManager.setVisibility(View.GONE); applistBinding.noAppFound.setVisibility(View.GONE); - ApplicationListAdapter adapter = new ApplicationListAdapter(packageManager, onAppClickListener); + adapter = new ApplicationListAdapter(packageManager, onAppClickListener); if(adapter.getItemCount() == 0) { applistBinding.noAppFound.setVisibility(View.VISIBLE); } else { @@ -170,4 +171,8 @@ public class AppListFragment extends Fragment { super.onDetach(); packageManager = null; } + + public void filter(String filter){ + adapter.filter(filter); + } } diff --git a/app/src/main/res/drawable-hdpi/ic_search.png b/app/src/main/res/drawable-hdpi/ic_search.png new file mode 100644 index 0000000..c53e331 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_search.png b/app/src/main/res/drawable-ldpi/ic_search.png new file mode 100644 index 0000000..d190496 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_search.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_search.png b/app/src/main/res/drawable-mdpi/ic_search.png new file mode 100644 index 0000000..5feb851 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_search.png b/app/src/main/res/drawable-xhdpi/ic_search.png new file mode 100644 index 0000000..3b17455 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_search.png b/app/src/main/res/drawable-xxhdpi/ic_search.png new file mode 100644 index 0000000..c635b4a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_search.png b/app/src/main/res/drawable-xxxhdpi/ic_search.png new file mode 100644 index 0000000..88f973d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_search.png differ diff --git a/app/src/main/res/layout/app_item_empty.xml b/app/src/main/res/layout/app_item_empty.xml new file mode 100644 index 0000000..b9d0efe --- /dev/null +++ b/app/src/main/res/layout/app_item_empty.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml new file mode 100644 index 0000000..2846266 --- /dev/null +++ b/app/src/main/res/menu/main.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b3336f9..776ff53 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -20,4 +20,7 @@ Traitement des pisteurs : Récupération des pisteurs : en attente de connexion au serveur Récupération des pisteurs + + + Filtrer diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5e9aa8..9e2a02e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,4 +20,7 @@ Processing Trackers: Getting trackers: Waiting for server connection Getting trackers + + + Filter