mirror of
https://github.com/stom79/exodus-android-app
synced 2024-12-22 13:43:54 +01:00
Merge branch 'borsini-feat/improve-application-startup-time'
This commit is contained in:
commit
a10cc837df
@ -18,6 +18,8 @@
|
||||
|
||||
package org.eu.exodus_privacy.exodusprivacy;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -82,24 +84,30 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
};
|
||||
|
||||
ApplicationListAdapter.OnAppClickListener onAppClickListener = packageInfo -> {
|
||||
ApplicationListAdapter.OnAppClickListener onAppClickListener = vm -> {
|
||||
try {
|
||||
PackageManager pm = getPackageManager();
|
||||
PackageInfo packageInfo = pm.getPackageInfo(vm.packageName, PackageManager.GET_PERMISSIONS);
|
||||
|
||||
report = ReportFragment.newInstance(getPackageManager(),packageInfo);
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_right, R.anim.slide_in_left, R.anim.slide_out_left)
|
||||
.replace(R.id.fragment_container,report)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
report = ReportFragment.newInstance(pm,packageInfo);
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_right, R.anim.slide_in_left, R.anim.slide_out_left)
|
||||
.replace(R.id.fragment_container,report)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
|
||||
packageName = packageInfo.packageName;
|
||||
packageName = packageInfo.packageName;
|
||||
|
||||
searchView.clearFocus();
|
||||
if (toolbarMenu != null)
|
||||
(toolbarMenu.findItem(R.id.action_filter)).collapseActionView();
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(mainBinding.fragmentContainer.getWindowToken(), 0);
|
||||
searchView.clearFocus();
|
||||
if (toolbarMenu != null)
|
||||
(toolbarMenu.findItem(R.id.action_filter)).collapseActionView();
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(mainBinding.fragmentContainer.getWindowToken(), 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
appList = AppListFragment.newInstance(networkListener,onAppClickListener);
|
||||
|
@ -19,21 +19,14 @@
|
||||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.databinding.DataBindingUtil;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
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;
|
||||
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
||||
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;
|
||||
|
||||
@ -47,14 +40,10 @@ import java.util.regex.Pattern;
|
||||
public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
|
||||
private List<ApplicationViewModel> applicationViewModels;
|
||||
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 Context context;
|
||||
|
||||
|
||||
private Comparator<ApplicationViewModel> alphaPackageComparator = new Comparator<ApplicationViewModel>() {
|
||||
@Override
|
||||
@ -63,83 +52,9 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
};
|
||||
|
||||
public ApplicationListAdapter(Context context, PackageManager manager, OnAppClickListener listener) {
|
||||
public ApplicationListAdapter(Context context, OnAppClickListener listener) {
|
||||
applicationViewModels = new ArrayList<>();
|
||||
onAppClickListener = listener;
|
||||
this.context = context;
|
||||
setPackageManager(manager);
|
||||
}
|
||||
|
||||
private void setInstalledPackages(List<PackageInfo> installedPackages) {
|
||||
List<ApplicationViewModel> viewModels = convertPackagesToViewModels(installedPackages);
|
||||
applyStoreFilter(viewModels);
|
||||
Collections.sort(viewModels, alphaPackageComparator);
|
||||
applicationViewModels = viewModels;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void applyStoreFilter(List<ApplicationViewModel> apps) {
|
||||
List<ApplicationViewModel> toRemove = new ArrayList<>();
|
||||
for (ApplicationViewModel app : apps) {
|
||||
if (!gStore.equals(app.installerPackageName)) {
|
||||
|
||||
String auid = Utils.getCertificateSHA1Fingerprint(packageManager,app.packageName);
|
||||
String appuid = DatabaseManager.getInstance(context).getAUID(app.packageName);
|
||||
if(!auid.equalsIgnoreCase(appuid)) {
|
||||
toRemove.add(app);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ApplicationInfo info = packageManager.getApplicationInfo(app.packageName,0);
|
||||
if(!info.enabled) {
|
||||
toRemove.add(app);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,17 +76,13 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
if( viewHolder.getItemViewType() == DISPLAYED_APP) {
|
||||
final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder;
|
||||
holder.setViewModel(applicationViewModels.get(position));
|
||||
ApplicationViewModel vm = applicationViewModels.get(position);
|
||||
holder.setViewModel(vm);
|
||||
//noinspection Convert2Lambda
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(holder.viewModel.packageName, PackageManager.GET_PERMISSIONS);
|
||||
onAppClickListener.onAppClick(packageInfo);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
onAppClickListener.onAppClick(vm);
|
||||
}
|
||||
});
|
||||
}else {
|
||||
@ -186,28 +97,10 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
return applicationViewModels.size();
|
||||
}
|
||||
|
||||
public void setPackageManager(PackageManager manager) {
|
||||
packageManager = manager;
|
||||
if(packageManager != null) {
|
||||
List<PackageInfo> installedPackages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
setInstalledPackages(installedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
public void displayAppList(List<ApplicationViewModel> applications) {
|
||||
applicationViewModels = applications;
|
||||
Collections.sort(applicationViewModels, alphaPackageComparator);
|
||||
filter(filter);
|
||||
}
|
||||
|
||||
class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{
|
||||
@ -284,7 +177,7 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
}
|
||||
|
||||
public interface OnAppClickListener {
|
||||
void onAppClick(PackageInfo packageInfo);
|
||||
void onAppClick(ApplicationViewModel vm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
@ -34,22 +34,25 @@ import android.view.ViewGroup;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.databinding.ApplistBinding;
|
||||
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.NetworkManager;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AppListFragment extends Fragment {
|
||||
public class AppListFragment extends Fragment implements ComputeAppListTask.Listener {
|
||||
|
||||
|
||||
private PackageManager packageManager;
|
||||
private @Nullable PackageManager packageManager;
|
||||
private NetworkListener networkListener;
|
||||
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||
private boolean startupRefresh;
|
||||
private ApplistBinding applistBinding;
|
||||
private ApplicationListAdapter adapter;
|
||||
private @Nullable ApplicationListAdapter adapter;
|
||||
private List<ApplicationViewModel> applications;
|
||||
|
||||
public static AppListFragment newInstance(NetworkListener networkListener, ApplicationListAdapter.OnAppClickListener appClickListener) {
|
||||
AppListFragment fragment = new AppListFragment();
|
||||
@ -62,6 +65,8 @@ public class AppListFragment extends Fragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
applications = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,13 +92,10 @@ public class AppListFragment extends Fragment {
|
||||
startupRefresh = false;
|
||||
}
|
||||
applistBinding.noPackageManager.setVisibility(View.GONE);
|
||||
applistBinding.noAppFound.setVisibility(View.GONE);
|
||||
adapter = new ApplicationListAdapter(getActivity().getApplicationContext(),packageManager, onAppClickListener);
|
||||
if(adapter.getItemCount() == 0) {
|
||||
applistBinding.noAppFound.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
applistBinding.appList.setAdapter(adapter);
|
||||
}
|
||||
adapter = new ApplicationListAdapter(context, onAppClickListener);
|
||||
applistBinding.appList.setAdapter(adapter);
|
||||
onAppsComputed(applications);
|
||||
displayAppListAsync();
|
||||
} else {
|
||||
applistBinding.noPackageManager.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@ -116,9 +118,7 @@ public class AppListFragment extends Fragment {
|
||||
if(applistBinding != null) {
|
||||
applistBinding.layoutProgress.setVisibility(View.GONE);
|
||||
applistBinding.swipeRefresh.setRefreshing(false);
|
||||
if(packageManager != null && applistBinding.appList.getAdapter() != null) {
|
||||
((ApplicationListAdapter) applistBinding.appList.getAdapter()).setPackageManager(packageManager);
|
||||
}
|
||||
displayAppListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +175,27 @@ public class AppListFragment extends Fragment {
|
||||
}
|
||||
|
||||
public void filter(String filter){
|
||||
adapter.filter(filter);
|
||||
if(adapter != null) {
|
||||
adapter.filter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayAppListAsync() {
|
||||
applistBinding.noAppFound.setVisibility(View.GONE);
|
||||
|
||||
new ComputeAppListTask(
|
||||
new WeakReference<>(packageManager),
|
||||
new WeakReference<>(DatabaseManager.getInstance(getActivity())),
|
||||
new WeakReference<>(this)
|
||||
).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsComputed(List<ApplicationViewModel> apps) {
|
||||
this.applications = apps;
|
||||
applistBinding.noAppFound.setVisibility(apps.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
if(adapter != null) {
|
||||
adapter.displayAppList(apps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,128 @@
|
||||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class ComputeAppListTask extends AsyncTask<Void, Void, List<ApplicationViewModel>> {
|
||||
|
||||
interface Listener {
|
||||
void onAppsComputed(List<ApplicationViewModel> apps);
|
||||
}
|
||||
|
||||
private static final String gStore = "com.android.vending";
|
||||
|
||||
private WeakReference<PackageManager> packageManagerRef;
|
||||
private WeakReference<DatabaseManager> databaseManagerRef;
|
||||
private WeakReference<Listener> listenerRef;
|
||||
|
||||
ComputeAppListTask(WeakReference<PackageManager> packageManagerRef,
|
||||
WeakReference<DatabaseManager> databaseManagerRef,
|
||||
WeakReference<Listener> listenerRef) {
|
||||
this.packageManagerRef = packageManagerRef;
|
||||
this.databaseManagerRef = databaseManagerRef;
|
||||
this.listenerRef = listenerRef;
|
||||
}
|
||||
|
||||
protected List<ApplicationViewModel> doInBackground(Void... params) {
|
||||
PackageManager packageManager = packageManagerRef.get();
|
||||
DatabaseManager databaseManager = databaseManagerRef.get();
|
||||
|
||||
List<ApplicationViewModel> vms = new ArrayList<>();
|
||||
if(packageManager != null && databaseManager != null) {
|
||||
List<PackageInfo> installedPackages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
applyStoreFilter(installedPackages, databaseManager, packageManager);
|
||||
vms = convertPackagesToViewModels(installedPackages, databaseManager, packageManager);
|
||||
}
|
||||
return vms;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<ApplicationViewModel> vms) {
|
||||
Listener listener = listenerRef.get();
|
||||
|
||||
if(listener != null) {
|
||||
listener.onAppsComputed(vms);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ApplicationViewModel> convertPackagesToViewModels(List<PackageInfo> infos,
|
||||
DatabaseManager databaseManager,
|
||||
PackageManager packageManager) {
|
||||
ArrayList<ApplicationViewModel> appsToBuild = new ArrayList<>(infos.size());
|
||||
for (PackageInfo pi : infos) {
|
||||
appsToBuild.add(buildViewModelFromPackageInfo(pi, databaseManager, packageManager));
|
||||
}
|
||||
return appsToBuild;
|
||||
}
|
||||
|
||||
private ApplicationViewModel buildViewModelFromPackageInfo(PackageInfo pi,
|
||||
DatabaseManager databaseManager,
|
||||
PackageManager packageManager) {
|
||||
ApplicationViewModel vm = new ApplicationViewModel();
|
||||
|
||||
vm.versionName = pi.versionName;
|
||||
vm.packageName = pi.packageName;
|
||||
vm.versionCode = pi.versionCode;
|
||||
vm.requestedPermissions = pi.requestedPermissions;
|
||||
|
||||
if (vm.versionName != null)
|
||||
vm.report = databaseManager.getReportFor(vm.packageName, vm.versionName);
|
||||
else {
|
||||
vm.report = databaseManager.getReportFor(vm.packageName, vm.versionCode);
|
||||
}
|
||||
|
||||
if (vm.report != null) {
|
||||
vm.trackers = databaseManager.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;
|
||||
}
|
||||
|
||||
private void applyStoreFilter(List<PackageInfo> packageInfos,
|
||||
DatabaseManager databaseManager,
|
||||
PackageManager packageManager) {
|
||||
List<PackageInfo> toRemove = new ArrayList<>();
|
||||
for (PackageInfo packageInfo : packageInfos) {
|
||||
String packageName = packageInfo.packageName;
|
||||
String installerPackageName = packageManager.getInstallerPackageName(packageName);
|
||||
if (!gStore.equals(installerPackageName)) {
|
||||
String auid = Utils.getCertificateSHA1Fingerprint(packageManager, packageName);
|
||||
String appuid = databaseManager.getAUID(packageName);
|
||||
if(!auid.equalsIgnoreCase(appuid)) {
|
||||
toRemove.add(packageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName,0);
|
||||
if(!appInfo.enabled) {
|
||||
toRemove.add(packageInfo);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
packageInfos.removeAll(toRemove);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user