Add toggle to hide system apps in app selection

Closes #789
This commit is contained in:
emanuele-f
2026-02-06 11:13:19 +01:00
parent 022960ec5b
commit be671a20fa
7 changed files with 94 additions and 51 deletions
@@ -48,6 +48,7 @@ public class AppsTogglesAdapter extends RecyclerView.Adapter<AppsTogglesAdapter.
private final Set<String> mCheckedItems;
private AppToggleListener mListener;
private String mFilter = "";
private boolean mShowSystemApps = false;
private List<AppDescriptor> mApps = new ArrayList<>();
private final List<AppDescriptor> mFilteredApps = new ArrayList<>();
private @Nullable RecyclerView mRecyclerView;
@@ -131,11 +132,15 @@ public class AppsTogglesAdapter extends RecyclerView.Adapter<AppsTogglesAdapter.
holder.icon.setImageDrawable(app.getIcon());
}
private boolean isFiltering() {
return !mFilter.isEmpty() || !mShowSystemApps;
}
private List<AppDescriptor> getApps() {
if(mFilter.isEmpty())
return mApps;
else
if(isFiltering())
return mFilteredApps;
else
return mApps;
}
@Override
@@ -165,6 +170,12 @@ public class AppsTogglesAdapter extends RecyclerView.Adapter<AppsTogglesAdapter.
if(mListener != null)
mListener.onAppToggled(app, checked);
if(!checked && !mShowSystemApps && app.isSystem()) {
getApps().remove(old_pos);
notifyItemRemoved(old_pos);
return;
}
List<AppDescriptor> apps = getApps();
// determine the new item position
@@ -214,10 +225,13 @@ public class AppsTogglesAdapter extends RecyclerView.Adapter<AppsTogglesAdapter.
private void refreshedFiteredApps() {
mFilteredApps.clear();
if(!mFilter.isEmpty()) {
if(isFiltering()) {
for(AppDescriptor app: mApps) {
if(app.matches(mFilter, false))
mFilteredApps.add(app);
if(!mFilter.isEmpty() && !app.matches(mFilter, false))
continue;
if(!mShowSystemApps && app.isSystem() && !mCheckedItems.contains(app.getPackageName()))
continue;
mFilteredApps.add(app);
}
}
@@ -235,6 +249,11 @@ public class AppsTogglesAdapter extends RecyclerView.Adapter<AppsTogglesAdapter.
refreshedFiteredApps();
}
public void setShowSystemApps(boolean show) {
mShowSystemApps = show;
refreshedFiteredApps();
}
public void setAppToggleListener(final AppToggleListener listener) {
mListener = listener;
}
@@ -53,6 +53,7 @@ import kotlin.NotImplementedError;
public abstract class AppsToggles extends Fragment implements AppsLoadListener,
AppsTogglesAdapter.AppToggleListener, MenuProvider, SearchView.OnQueryTextListener {
private static final String TAG = "AppsToggles";
private static boolean sShowSystemApps;
private AppsTogglesAdapter mAdapter;
private SearchView mSearchView;
private TextView mEmptyText;
@@ -84,6 +85,8 @@ public abstract class AppsToggles extends Fragment implements AppsLoadListener,
mQueryToApply = filter;
}
mAdapter.setShowSystemApps(sShowSystemApps);
Log.d(TAG, "mQueryToApply: " + mQueryToApply);
(new AppsLoader((AppCompatActivity) requireActivity()))
@@ -110,10 +113,20 @@ public abstract class AppsToggles extends Fragment implements AppsLoadListener,
Log.d(TAG, "Initial filter: " + mQueryToApply);
Utils.setSearchQuery(mSearchView, searchItem, mQueryToApply);
}
MenuItem systemAppsItem = menu.findItem(R.id.show_system_apps);
if(systemAppsItem != null)
systemAppsItem.setChecked(sShowSystemApps);
}
@Override
public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
if(menuItem.getItemId() == R.id.show_system_apps) {
sShowSystemApps = !sShowSystemApps;
menuItem.setChecked(sShowSystemApps);
mAdapter.setShowSystemApps(sShowSystemApps);
return true;
}
return false;
}
@@ -22,6 +22,7 @@ package com.emanuelef.remote_capture.views;
import android.app.Dialog;
import android.content.SharedPreferences;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
@@ -42,6 +43,7 @@ import java.util.List;
public class AppSelectDialog implements AppsLoadListener {
private static final String TAG = "AppSelectDialog";
private static boolean sShowSystemApps;
private AppsListView mOpenAppsList;
private TextView mEmptyAppsView;
private Dialog mDialog;
@@ -122,6 +124,14 @@ public class AppSelectDialog implements AppsLoadListener {
apps.setEmptyView(emptyText);
searchView.setOnQueryTextListener(apps);
CheckBox showSystemApps = dialogLayout.findViewById(R.id.show_system_apps);
showSystemApps.setChecked(sShowSystemApps);
apps.setShowSystemApps(sShowSystemApps);
showSystemApps.setOnCheckedChangeListener((buttonView, isChecked) -> {
sShowSystemApps = isChecked;
apps.setShowSystemApps(isChecked);
});
AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(mActivity);
builder.setTitle(mTitleRes);
builder.setView(dialogLayout);
@@ -21,9 +21,6 @@ package com.emanuelef.remote_capture.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Filter;
import android.widget.Filterable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
@@ -34,10 +31,11 @@ import com.emanuelef.remote_capture.model.AppDescriptor;
import java.util.ArrayList;
import java.util.List;
public class AppsListView extends EmptyRecyclerView implements SearchView.OnQueryTextListener, Filterable {
public class AppsListView extends EmptyRecyclerView implements SearchView.OnQueryTextListener {
private List<AppDescriptor> mAllApps;
private AppsAdapter mAdapter;
private String mLastFilter;
private boolean mShowSystemApps;
public AppsListView(@NonNull Context context) {
super(context);
@@ -60,42 +58,6 @@ public class AppsListView extends EmptyRecyclerView implements SearchView.OnQuer
setHasFixedSize(true);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString().toLowerCase();
List<AppDescriptor> appsFiltered;
if(charString.isEmpty())
appsFiltered = mAllApps;
else {
appsFiltered = new ArrayList<>();
for(AppDescriptor app : mAllApps) {
if(app.getPackageName().toLowerCase().contains(charString)
|| app.getName().toLowerCase().contains(charString)) {
appsFiltered.add(app);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = appsFiltered;
return filterResults;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<AppDescriptor> appsFiltered = (List<AppDescriptor>) results.values;
mAdapter.setApps(appsFiltered);
}
};
}
@Override
public boolean onQueryTextSubmit(String query) {
return true;
@@ -104,7 +66,8 @@ public class AppsListView extends EmptyRecyclerView implements SearchView.OnQuer
@Override
public boolean onQueryTextChange(String newText) {
mLastFilter = newText;
getFilter().filter(newText);
if(mAllApps != null)
mAdapter.setApps(getFilteredApps());
return true;
}
@@ -112,17 +75,40 @@ public class AppsListView extends EmptyRecyclerView implements SearchView.OnQuer
void onSelectedApp(AppDescriptor app);
}
private List<AppDescriptor> getFilteredApps() {
String filter = (mLastFilter != null) ? mLastFilter.toLowerCase() : "";
if(filter.isEmpty() && mShowSystemApps)
return mAllApps;
List<AppDescriptor> filtered = new ArrayList<>();
for(AppDescriptor app : mAllApps) {
if(!mShowSystemApps && app.isSystem())
continue;
if(!filter.isEmpty()
&& !app.getPackageName().toLowerCase().contains(filter)
&& !app.getName().toLowerCase().contains(filter))
continue;
filtered.add(app);
}
return filtered;
}
public void setApps(List<AppDescriptor> installedApps) {
mAllApps = installedApps;
List<AppDescriptor> apps = getFilteredApps();
if(mAdapter == null) {
mAdapter = new AppsAdapter(getContext(), mAllApps);
mAdapter = new AppsAdapter(getContext(), apps);
setAdapter(mAdapter);
} else
mAdapter.setApps(mAllApps);
mAdapter.setApps(apps);
}
if(mLastFilter != null)
getFilter().filter(mLastFilter);
public void setShowSystemApps(boolean show) {
mShowSystemApps = show;
if(mAllApps != null)
mAdapter.setApps(getFilteredApps());
}
public void setSelectedAppListener(final OnSelectedAppListener listener) {
@@ -13,6 +13,14 @@
app:iconifiedByDefault="false"
app:queryHint="@string/search_apps"/>
<CheckBox
android:id="@+id/show_system_apps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="@string/show_system_apps" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
+6
View File
@@ -9,4 +9,10 @@
android:icon="@drawable/ic_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom" />
<item
android:id="@+id/show_system_apps"
android:title="@string/show_system_apps"
android:checkable="true"
app:showAsAction="never" />
</menu>
+1
View File
@@ -452,6 +452,7 @@
<string name="requesting_unlock_token">Requesting an unlock token, please wait</string>
<string name="show_action">Show</string>
<string name="show_connection">Show connection</string>
<string name="show_system_apps">Show system apps</string>
<string name="unlock_token_msg1">This is your unlock token. Note it down as you will need it <a href='%1$s'>to generate your license codes</a></string>
<string name="paid_feature">Paid feature</string>
<string name="firewall_purchase_msg">Buy the <i>%1$s</i> feature to start blocking connections</string>