2018-02-20 13:54:18 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2018 Anthony Chomienne, anthony@mob-dev.fr
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 3
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
|
|
|
|
2018-04-11 15:27:05 +02:00
|
|
|
import android.content.Context;
|
2018-08-31 18:36:01 +02:00
|
|
|
import android.content.pm.ApplicationInfo;
|
2018-02-20 13:54:18 +01:00
|
|
|
import android.content.pm.PackageInfo;
|
|
|
|
import android.content.pm.PackageManager;
|
2018-04-11 15:27:05 +02:00
|
|
|
import android.databinding.DataBindingUtil;
|
2019-05-26 21:21:05 +02:00
|
|
|
import android.graphics.drawable.Drawable;
|
2018-04-14 14:37:51 +02:00
|
|
|
import android.support.annotation.NonNull;
|
2019-05-26 21:21:05 +02:00
|
|
|
import android.support.annotation.Nullable;
|
2018-02-20 13:54:18 +01:00
|
|
|
import android.support.v7.widget.RecyclerView;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
2018-08-31 15:35:42 +02:00
|
|
|
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
2018-04-11 15:27:05 +02:00
|
|
|
import org.eu.exodus_privacy.exodusprivacy.databinding.AppItemBinding;
|
2018-02-20 13:54:18 +01:00
|
|
|
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
|
|
|
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
|
|
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
2018-08-31 15:35:42 +02:00
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Comparator;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
2018-04-14 14:37:51 +02:00
|
|
|
import java.util.regex.Pattern;
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2018-04-14 14:37:51 +02:00
|
|
|
public class ApplicationListAdapter extends RecyclerView.Adapter {
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
private List<ApplicationViewModel> applicationViewModels;
|
2018-02-20 13:54:18 +01:00
|
|
|
private PackageManager packageManager;
|
|
|
|
private OnAppClickListener onAppClickListener;
|
2018-04-11 15:27:05 +02:00
|
|
|
private static final String gStore = "com.android.vending";
|
2018-04-14 14:37:51 +02:00
|
|
|
private String filter = "";
|
|
|
|
private final int HIDDEN_APP = 0;
|
|
|
|
private final int DISPLAYED_APP = 1;
|
2018-08-31 15:35:42 +02:00
|
|
|
private Context context;
|
2018-04-14 14:37:51 +02:00
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
private Comparator<ApplicationViewModel> alphaPackageComparator = new Comparator<ApplicationViewModel>() {
|
2018-02-20 13:54:18 +01:00
|
|
|
@Override
|
2019-05-26 21:21:05 +02:00
|
|
|
public int compare(ApplicationViewModel app1, ApplicationViewModel app2) {
|
|
|
|
return app1.label.toString().compareToIgnoreCase(app2.label.toString());
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-31 15:35:42 +02:00
|
|
|
public ApplicationListAdapter(Context context, PackageManager manager, OnAppClickListener listener) {
|
2019-05-26 21:21:05 +02:00
|
|
|
applicationViewModels = new ArrayList<>();
|
2018-02-20 13:54:18 +01:00
|
|
|
onAppClickListener = listener;
|
2018-08-31 15:35:42 +02:00
|
|
|
this.context = context;
|
2019-06-06 20:56:16 +02:00
|
|
|
displayApplicationList(manager);
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void setInstalledPackages(List<PackageInfo> installedPackages) {
|
2019-05-26 21:21:05 +02:00
|
|
|
List<ApplicationViewModel> viewModels = convertPackagesToViewModels(installedPackages);
|
|
|
|
applyStoreFilter(viewModels);
|
|
|
|
Collections.sort(viewModels, alphaPackageComparator);
|
|
|
|
applicationViewModels = viewModels;
|
2018-02-20 13:54:18 +01:00
|
|
|
notifyDataSetChanged();
|
|
|
|
}
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
private void applyStoreFilter(List<ApplicationViewModel> apps) {
|
|
|
|
List<ApplicationViewModel> toRemove = new ArrayList<>();
|
|
|
|
for (ApplicationViewModel app : apps) {
|
|
|
|
if (!gStore.equals(app.installerPackageName)) {
|
2018-08-31 18:36:01 +02:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
String auid = Utils.getCertificateSHA1Fingerprint(packageManager,app.packageName);
|
|
|
|
String appuid = DatabaseManager.getInstance(context).getAUID(app.packageName);
|
2018-08-31 15:35:42 +02:00
|
|
|
if(!auid.equalsIgnoreCase(appuid)) {
|
2019-05-26 21:21:05 +02:00
|
|
|
toRemove.add(app);
|
2018-08-31 15:35:42 +02:00
|
|
|
}
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
2018-08-31 18:36:01 +02:00
|
|
|
|
|
|
|
try {
|
2019-05-26 21:21:05 +02:00
|
|
|
ApplicationInfo info = packageManager.getApplicationInfo(app.packageName,0);
|
2018-08-31 18:36:01 +02:00
|
|
|
if(!info.enabled) {
|
2019-05-26 21:21:05 +02:00
|
|
|
toRemove.add(app);
|
2018-08-31 18:36:01 +02:00
|
|
|
}
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
2019-05-26 21:21:05 +02:00
|
|
|
apps.removeAll(toRemove);
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<ApplicationViewModel> convertPackagesToViewModels(List<PackageInfo> infos) {
|
|
|
|
ArrayList<ApplicationViewModel> appsToBuild = new ArrayList<>(infos.size());
|
|
|
|
for (PackageInfo pi : infos) {
|
|
|
|
appsToBuild.add(buildViewModelFromPackageInfo(pi));
|
|
|
|
}
|
|
|
|
return appsToBuild;
|
|
|
|
}
|
|
|
|
|
|
|
|
private ApplicationViewModel buildViewModelFromPackageInfo(PackageInfo pi) {
|
|
|
|
ApplicationViewModel vm = new ApplicationViewModel();
|
|
|
|
|
|
|
|
vm.versionName = pi.versionName;
|
|
|
|
vm.packageName = pi.packageName;
|
|
|
|
vm.versionCode = pi.versionCode;
|
|
|
|
vm.requestedPermissions = pi.requestedPermissions;
|
|
|
|
|
|
|
|
DatabaseManager dm = DatabaseManager.getInstance(context);
|
|
|
|
if(vm.versionName != null)
|
|
|
|
vm.report = dm.getReportFor(vm.packageName, vm.versionName);
|
|
|
|
else {
|
|
|
|
vm.report = dm.getReportFor(vm.packageName, vm.versionCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(vm.report != null) {
|
|
|
|
vm.trackers = dm.getTrackers(vm.report.trackers);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
vm.icon = packageManager.getApplicationIcon(vm.packageName);
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
vm.label = packageManager.getApplicationLabel(pi.applicationInfo);
|
|
|
|
vm.installerPackageName = packageManager.getInstallerPackageName(vm.packageName);
|
|
|
|
vm.isVisible = true;
|
|
|
|
|
|
|
|
return vm;
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2018-04-14 14:37:51 +02:00
|
|
|
public int getItemViewType(int position){
|
2019-05-26 21:21:05 +02:00
|
|
|
return applicationViewModels.get(position).isVisible ? DISPLAYED_APP : HIDDEN_APP;
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2018-04-14 14:37:51 +02:00
|
|
|
@NonNull
|
2018-02-20 13:54:18 +01:00
|
|
|
@Override
|
2018-04-14 14:37:51 +02:00
|
|
|
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));
|
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2018-04-14 14:37:51 +02:00
|
|
|
@Override
|
|
|
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
|
|
|
if( viewHolder.getItemViewType() == DISPLAYED_APP) {
|
|
|
|
final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder;
|
2019-05-26 21:21:05 +02:00
|
|
|
holder.setViewModel(applicationViewModels.get(position));
|
2018-04-14 14:37:51 +02:00
|
|
|
//noinspection Convert2Lambda
|
|
|
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
2019-05-26 21:21:05 +02:00
|
|
|
try {
|
2019-05-29 17:40:51 +02:00
|
|
|
PackageInfo packageInfo = packageManager.getPackageInfo(holder.viewModel.packageName, PackageManager.GET_PERMISSIONS);
|
2019-05-26 21:21:05 +02:00
|
|
|
onAppClickListener.onAppClick(packageInfo);
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2018-04-14 14:37:51 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}else {
|
|
|
|
//noinspection unused
|
|
|
|
final ApplicationEmptyViewHolder holder = (ApplicationEmptyViewHolder) viewHolder;
|
|
|
|
//If something should be done for app that are hidden, it's here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
@Override
|
|
|
|
public int getItemCount() {
|
2019-05-26 21:21:05 +02:00
|
|
|
return applicationViewModels.size();
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 20:56:16 +02:00
|
|
|
public void displayApplicationList(PackageManager manager) {
|
2018-02-20 13:54:18 +01:00
|
|
|
packageManager = manager;
|
2018-04-11 15:27:05 +02:00
|
|
|
if(packageManager != null) {
|
|
|
|
List<PackageInfo> installedPackages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
|
|
|
setInstalledPackages(installedPackages);
|
|
|
|
}
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
/**
|
|
|
|
* This class holds the data needed to display an application cell in the RecyclerView
|
|
|
|
*/
|
|
|
|
public class ApplicationViewModel {
|
|
|
|
public String packageName;
|
|
|
|
public String versionName;
|
|
|
|
public int versionCode;
|
|
|
|
public String[] requestedPermissions;
|
|
|
|
public @Nullable Report report;
|
|
|
|
public Set<Tracker> trackers;
|
|
|
|
public @Nullable Drawable icon;
|
|
|
|
public CharSequence label;
|
|
|
|
public String installerPackageName;
|
|
|
|
public boolean isVisible;
|
|
|
|
}
|
|
|
|
|
2018-04-14 14:37:51 +02:00
|
|
|
class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{
|
|
|
|
ApplicationEmptyViewHolder(View itemView) {
|
|
|
|
super(itemView);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
class ApplicationListViewHolder extends RecyclerView.ViewHolder {
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
ApplicationViewModel viewModel;
|
2018-04-11 15:27:05 +02:00
|
|
|
AppItemBinding appItemBinding;
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2018-04-11 15:27:05 +02:00
|
|
|
ApplicationListViewHolder(AppItemBinding binding) {
|
|
|
|
super(binding.getRoot());
|
|
|
|
appItemBinding = binding;
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
void setViewModel(ApplicationViewModel vm) {
|
|
|
|
viewModel = vm;
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2018-04-11 15:27:05 +02:00
|
|
|
Context context = appItemBinding.getRoot().getContext();
|
|
|
|
|
2018-02-20 13:54:18 +01:00
|
|
|
//reinit view state
|
2018-04-11 15:27:05 +02:00
|
|
|
appItemBinding.otherVersion.setVisibility(View.GONE);
|
|
|
|
appItemBinding.analysed.setVisibility(View.GONE);
|
|
|
|
appItemBinding.appTrackerNb.setVisibility(View.VISIBLE);
|
2019-01-08 18:56:36 +01:00
|
|
|
appItemBinding.appTracker.setVisibility(View.VISIBLE);
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
String versionName = viewModel.versionName;
|
|
|
|
long versionCode = viewModel.versionCode;
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
appItemBinding.appLogo.setImageDrawable(viewModel.icon);
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
appItemBinding.appName.setText(viewModel.label);
|
2018-02-20 13:54:18 +01:00
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
long size = viewModel.requestedPermissions != null ? viewModel.requestedPermissions.length : 0;
|
2019-01-08 18:56:36 +01:00
|
|
|
appItemBinding.appPermissionNb.setText(String.valueOf(size));
|
|
|
|
if(size == 0)
|
|
|
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_green);
|
|
|
|
else if (size < 5)
|
|
|
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_yellow);
|
|
|
|
else
|
|
|
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_red);
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
Report report = viewModel.report;
|
2018-02-20 13:54:18 +01:00
|
|
|
if(report != null) {
|
2019-05-26 21:21:05 +02:00
|
|
|
Set<Tracker> trackers = viewModel.trackers;
|
2019-01-08 18:56:36 +01:00
|
|
|
|
|
|
|
size = trackers.size();
|
|
|
|
appItemBinding.appTrackerNb.setText(String.valueOf(size));
|
|
|
|
if(size == 0)
|
|
|
|
appItemBinding.appTrackerNb.setBackgroundResource(R.drawable.square_green);
|
|
|
|
else if (size < 5)
|
|
|
|
appItemBinding.appTrackerNb.setBackgroundResource(R.drawable.square_yellow);
|
|
|
|
else
|
|
|
|
appItemBinding.appTrackerNb.setBackgroundResource(R.drawable.square_red);
|
|
|
|
|
2019-05-26 21:21:05 +02:00
|
|
|
if(versionName != null && !report.version.equals(viewModel.versionName)) {
|
|
|
|
String string = context.getString(R.string.tested,versionName, report.version);
|
2019-02-21 23:16:42 +01:00
|
|
|
appItemBinding.otherVersion.setText(string);
|
2019-01-08 18:17:37 +01:00
|
|
|
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
|
|
|
} else if (versionName == null && report.versionCode != versionCode) {
|
2019-02-21 23:16:42 +01:00
|
|
|
String string = context.getString(R.string.tested,String.valueOf(versionCode),String.valueOf(report.versionCode));
|
|
|
|
appItemBinding.otherVersion.setText(string);
|
2018-04-11 15:27:05 +02:00
|
|
|
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
} else {
|
2018-04-11 15:27:05 +02:00
|
|
|
appItemBinding.appTrackerNb.setVisibility(View.GONE);
|
2019-01-08 18:56:36 +01:00
|
|
|
appItemBinding.appTracker.setVisibility(View.GONE);
|
2018-04-11 15:27:05 +02:00
|
|
|
appItemBinding.analysed.setVisibility(View.VISIBLE);
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface OnAppClickListener {
|
|
|
|
void onAppClick(PackageInfo packageInfo);
|
|
|
|
}
|
2018-04-14 14:37:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
public void filter(String text) {
|
|
|
|
filter = text;
|
2019-05-26 21:21:05 +02:00
|
|
|
|
|
|
|
Pattern p = Pattern.compile(Pattern.quote(filter.trim()), Pattern.CASE_INSENSITIVE);
|
|
|
|
for (ApplicationViewModel app : applicationViewModels) {
|
|
|
|
app.isVisible = p.matcher(app.label).find();
|
|
|
|
}
|
|
|
|
|
2018-04-14 14:37:51 +02:00
|
|
|
notifyDataSetChanged();
|
|
|
|
}
|
2018-02-20 13:54:18 +01:00
|
|
|
}
|