Merge branch 'master' into stom79_baseline
# Conflicts: # app/src/main/java/org/eu/exodus_privacy/exodusprivacy/MainActivity.java # app/src/main/java/org/eu/exodus_privacy/exodusprivacy/fragments/AppListFragment.java
|
@ -8,8 +8,6 @@ gen/
|
||||||
.gradle/
|
.gradle/
|
||||||
build/
|
build/
|
||||||
/*/build/
|
/*/build/
|
||||||
gradlew*
|
|
||||||
gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
# Local configuration file (sdk path, etc)
|
||||||
local.properties
|
local.properties
|
||||||
|
@ -24,4 +22,10 @@ proguard/
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
|
#vim
|
||||||
|
.*swp
|
||||||
|
.*swo
|
||||||
|
.tags
|
||||||
|
|
||||||
|
|
||||||
captures/
|
captures/
|
||||||
|
|
29
.travis.yml
|
@ -1,23 +1,26 @@
|
||||||
language: android
|
language: android
|
||||||
java: oraclejdk8
|
java: oraclejdk8
|
||||||
cache: false
|
|
||||||
|
before_cache:
|
||||||
|
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||||
|
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.gradle/caches/
|
||||||
|
- $HOME/.gradle/wrapper/
|
||||||
|
- $HOME/.android/build-cache
|
||||||
|
|
||||||
android:
|
android:
|
||||||
componentes:
|
components:
|
||||||
- tools
|
- tools
|
||||||
- platform-tools
|
- platform-tools
|
||||||
- tools
|
- build-tools-29.0.3
|
||||||
|
- android-29
|
||||||
- build-tools-27.0.3
|
|
||||||
- android-27
|
|
||||||
- extra-m2-repository
|
- extra-m2-repository
|
||||||
- sys-img-armeabi-v7a-android-27
|
- sys-img-armeabi-v7a-android-28
|
||||||
|
|
||||||
before_script:
|
|
||||||
- mkdir "$ANDROID_HOME/licenses" || true
|
|
||||||
- echo -e "\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license"
|
|
||||||
- touch empty.file
|
|
||||||
- gradle wrapper --gradle-version 4.1 -b empty.file
|
|
||||||
- rm empty.file
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./gradlew assembleDebug
|
- ./gradlew assembleDebug
|
||||||
|
- ./gradlew test
|
||||||
|
|
|
@ -3,3 +3,8 @@
|
||||||
Exodus Privacy is an Android application.
|
Exodus Privacy is an Android application.
|
||||||
Exodus Privacy application let you know what trackers are embedded in apps installed on your smartphone. It let you also know the permissions required by any apps on your smartphone.
|
Exodus Privacy application let you know what trackers are embedded in apps installed on your smartphone. It let you also know the permissions required by any apps on your smartphone.
|
||||||
It helps you to take your privacy back!
|
It helps you to take your privacy back!
|
||||||
|
|
||||||
|
<a href="https://f-droid.org/packages/org.eu.exodus_privacy.exodusprivacy/" target="_blank">
|
||||||
|
<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80"/></a>
|
||||||
|
<a href="https://play.google.com/store/apps/details?id=org.eu.exodus_privacy.exodusprivacy" target="_blank">
|
||||||
|
<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" alt="Get it on Google Play" height="80"/></a>
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 29
|
||||||
buildToolsVersion "27.0.3"
|
buildToolsVersion "29.0.3"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
||||||
minSdkVersion 16
|
minSdkVersion 17
|
||||||
targetSdkVersion 27
|
targetSdkVersion 29
|
||||||
versionCode 4
|
versionCode 10
|
||||||
versionName "1.0.4"
|
versionName "2.1.1"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -24,19 +24,20 @@ android {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
dataBinding {
|
buildFeatures {
|
||||||
enabled = true
|
dataBinding = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||||
exclude group: 'com.android.support', module: 'support-annotations'
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
})
|
})
|
||||||
compile 'com.android.support:appcompat-v7:27.1.0'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
compile 'com.android.support:design:27.1.0'
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
compile 'com.android.support:recyclerview-v7:27.1.0'
|
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||||
testCompile 'junit:junit:4.12'
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
testImplementation 'junit:junit:4.13'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.eu.exodus_privacy.exodusprivacy">
|
package="org.eu.exodus_privacy.exodusprivacy">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
@ -11,16 +12,17 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
|
tools:ignore="GoogleAppIndexingWarning"
|
||||||
|
android:largeHeap="true"
|
||||||
>
|
>
|
||||||
<activity android:name=".MainActivity"
|
<activity android:name=".MainActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
>
|
>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -18,52 +18,83 @@
|
||||||
|
|
||||||
package org.eu.exodus_privacy.exodusprivacy;
|
package org.eu.exodus_privacy.exodusprivacy;
|
||||||
|
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.content.pm.PackageInfo;
|
||||||
import android.app.SearchManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.databinding.DataBindingUtil;
|
import android.content.Intent;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.net.Uri;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.widget.SearchView;
|
import android.provider.Settings;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.SearchView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.databinding.MainBinding;
|
import org.eu.exodus_privacy.exodusprivacy.databinding.MainBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.fragments.AppListFragment;
|
import org.eu.exodus_privacy.exodusprivacy.fragments.HomeFragment;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.fragments.ReportFragment;
|
import org.eu.exodus_privacy.exodusprivacy.fragments.ReportFragment;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.fragments.TrackerFragment;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.fragments.Updatable;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
AppListFragment appList;
|
private List<Updatable> fragments;
|
||||||
ReportFragment report;
|
private SearchView searchView;
|
||||||
SearchView searchView;
|
private Menu toolbarMenu;
|
||||||
private Menu mMenu;
|
private MenuItem settingsMenuItem;
|
||||||
|
private String packageName;
|
||||||
|
private MainBinding binding;
|
||||||
|
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final MainBinding mainBinding = DataBindingUtil.setContentView(this,R.layout.main);
|
binding = DataBindingUtil.setContentView(this,R.layout.main);
|
||||||
|
final MainBinding mainBinding = binding;
|
||||||
|
getSupportActionBar().setTitle(R.string.app_title);
|
||||||
|
fragments = new ArrayList<>();
|
||||||
|
|
||||||
NetworkListener networkListener = new NetworkListener() {
|
NetworkListener networkListener = new NetworkListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess() {
|
public void onSuccess() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
appList.updateComplete();
|
for(Updatable updatable : fragments){
|
||||||
if(report != null)
|
if(updatable instanceof ReportFragment) {
|
||||||
report.updateComplete();
|
ApplicationViewModel model = ((ReportFragment) updatable).getModel();
|
||||||
|
if(model.versionName == null)
|
||||||
|
model.report = DatabaseManager.getInstance(MainActivity.this).getReportFor(model.packageName, model.versionCode, model.source);
|
||||||
|
else
|
||||||
|
model.report = DatabaseManager.getInstance(MainActivity.this).getReportFor(model.packageName,model.versionName,model.source);
|
||||||
|
if(model.report != null)
|
||||||
|
model.trackers = DatabaseManager.getInstance(MainActivity.this).getTrackers(model.report.trackers);
|
||||||
|
}
|
||||||
|
updatable.onUpdateComplete();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(String error) {
|
public void onError(String error) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
appList.updateComplete();
|
for(Updatable updatable : fragments){
|
||||||
|
updatable.onUpdateComplete();
|
||||||
|
}
|
||||||
Snackbar bar = Snackbar.make(mainBinding.fragmentContainer,error,Snackbar.LENGTH_LONG);
|
Snackbar bar = Snackbar.make(mainBinding.fragmentContainer,error,Snackbar.LENGTH_LONG);
|
||||||
bar.show();
|
bar.show();
|
||||||
});
|
});
|
||||||
|
@ -75,45 +106,72 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplicationListAdapter.OnAppClickListener onAppClickListener = packageInfo -> {
|
TrackerListAdapter.OnTrackerClickListener onTrackerClickListener = id -> {
|
||||||
|
TrackerFragment tracker = TrackerFragment.newInstance(id);
|
||||||
report = ReportFragment.newInstance(getPackageManager(),packageInfo);
|
tracker.setOnAppClickListener(onAppClickListener);
|
||||||
|
fragments.add(tracker);
|
||||||
FragmentManager manager = getSupportFragmentManager();
|
FragmentManager manager = getSupportFragmentManager();
|
||||||
FragmentTransaction transaction = manager.beginTransaction();
|
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)
|
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)
|
.replace(R.id.fragment_container,tracker)
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commit();
|
.commit();
|
||||||
searchView.clearFocus();
|
|
||||||
if (mMenu != null)
|
|
||||||
(mMenu.findItem(R.id.action_filter)).collapseActionView();
|
|
||||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
assert imm != null;
|
|
||||||
imm.hideSoftInputFromWindow(mainBinding.fragmentContainer.getWindowToken(), 0);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
appList = AppListFragment.newInstance(networkListener,onAppClickListener);
|
onAppClickListener = vm -> {
|
||||||
|
try {
|
||||||
|
PackageManager pm = getPackageManager();
|
||||||
|
PackageInfo packageInfo = pm.getPackageInfo(vm.packageName, PackageManager.GET_PERMISSIONS);
|
||||||
|
|
||||||
|
ReportFragment report = ReportFragment.newInstance(pm,vm,packageInfo,onTrackerClickListener);
|
||||||
|
fragments.add(report);
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HomeFragment home = new HomeFragment();
|
||||||
|
fragments.add(home);
|
||||||
|
home.setNetworkListener(networkListener);
|
||||||
|
home.setOnAppClickListener(onAppClickListener);
|
||||||
|
|
||||||
|
|
||||||
FragmentManager manager = getSupportFragmentManager();
|
FragmentManager manager = getSupportFragmentManager();
|
||||||
FragmentTransaction transaction = manager.beginTransaction();
|
FragmentTransaction transaction = manager.beginTransaction();
|
||||||
transaction.replace(R.id.fragment_container,appList)
|
transaction.replace(R.id.fragment_container,home)
|
||||||
.commit();
|
.commit();
|
||||||
|
home.startRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (getSupportFragmentManager().getBackStackEntryCount() == 0)
|
if (getSupportFragmentManager().getBackStackEntryCount() == 0)
|
||||||
finish();
|
finish();
|
||||||
else
|
else {
|
||||||
getSupportFragmentManager().popBackStack();
|
getSupportFragmentManager().popBackStack();
|
||||||
|
fragments.remove(fragments.size()-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
mMenu = menu;
|
toolbarMenu = menu;
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.main, menu);
|
inflater.inflate(R.menu.main, menu);
|
||||||
searchView = (SearchView) menu.findItem(R.id.action_filter).getActionView();
|
searchView = (SearchView) menu.findItem(R.id.action_filter).getActionView();
|
||||||
|
@ -121,16 +179,41 @@ public class MainActivity extends AppCompatActivity {
|
||||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextSubmit(String query) {
|
public boolean onQueryTextSubmit(String query) {
|
||||||
appList.filter(query);
|
HomeFragment home = (HomeFragment) fragments.get(0);
|
||||||
|
home.filter(query);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextChange(String newText) {
|
public boolean onQueryTextChange(String newText) {
|
||||||
appList.filter(newText);
|
HomeFragment home = (HomeFragment) fragments.get(0);
|
||||||
|
home.filter(newText);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
settingsMenuItem = menu.findItem(R.id.action_settings);
|
||||||
|
Updatable fragment = fragments.get(fragments.size()-1);
|
||||||
|
if (fragment instanceof ReportFragment)
|
||||||
|
settingsMenuItem.setVisible(true);
|
||||||
|
else
|
||||||
|
settingsMenuItem.setVisible(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if(item.getItemId() == R.id.action_settings) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
|
intent.setData(Uri.fromParts("package",packageName,null));
|
||||||
|
try {
|
||||||
|
startActivity(intent);
|
||||||
|
} catch(android.content.ActivityNotFoundException e) {
|
||||||
|
Snackbar bar = Snackbar.make(binding.fragmentContainer,R.string.no_settings,Snackbar.LENGTH_LONG);
|
||||||
|
bar.show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.databinding.BaseObservable;
|
||||||
|
import androidx.databinding.Bindable;
|
||||||
|
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.Permission;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.ReportDisplay;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
|
||||||
|
public class ReportViewModel extends BaseObservable {
|
||||||
|
private ReportDisplay reportDisplay;
|
||||||
|
|
||||||
|
public void setReportDisplay(ReportDisplay report){
|
||||||
|
this.reportDisplay = report;
|
||||||
|
notifyChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getName() {
|
||||||
|
return reportDisplay.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public Drawable getLogo() {
|
||||||
|
return reportDisplay.logo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getPermissionNumber() {
|
||||||
|
return reportDisplay.permissions != null ? reportDisplay.permissions.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getPermissionNumberStr() {
|
||||||
|
return String.valueOf(getPermissionNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public int getPermissionColor() {
|
||||||
|
return getColor(getPermissionNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getPermissionVisibility() {
|
||||||
|
return reportDisplay.permissions != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getHasPermissionDangerous() {
|
||||||
|
for(Permission perm : reportDisplay.permissions) {
|
||||||
|
if(perm.dangerous)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTrackerNumber() {
|
||||||
|
return reportDisplay.trackers != null ? reportDisplay.trackers.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getTrackerNumberStr() {
|
||||||
|
return String.valueOf(getTrackerNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getTrackerVisibility() {
|
||||||
|
return reportDisplay.trackers != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public int getTrackerColor() {
|
||||||
|
return getColor(getTrackerNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreator(Context context) {
|
||||||
|
String creator = reportDisplay.creator != null ? reportDisplay.creator : "";
|
||||||
|
if (reportDisplay.report != null && !reportDisplay.report.downloads.isEmpty()) {
|
||||||
|
String download = reportDisplay.report.downloads;
|
||||||
|
download = download.replace("downloads",context.getString(R.string.downloads));
|
||||||
|
creator += " (" + download + ")";
|
||||||
|
}
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getCreatorVisibility() {
|
||||||
|
return reportDisplay.creator != null && !reportDisplay.creator.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getInstalledVersion() {
|
||||||
|
return reportDisplay.versionName != null ? reportDisplay.versionName : String.valueOf(reportDisplay.versionCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getReportVersion() {
|
||||||
|
if(reportDisplay.report != null) {
|
||||||
|
if (reportDisplay.versionName != null && !reportDisplay.report.version.equals(reportDisplay.versionName)) {
|
||||||
|
return reportDisplay.report.version;
|
||||||
|
} else if (reportDisplay.versionName == null && reportDisplay.report.versionCode != reportDisplay.versionCode) {
|
||||||
|
return String.valueOf(reportDisplay.report.versionCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getReportVersionVisibility() {
|
||||||
|
return !getReportVersion().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public boolean getReportVisibility() {
|
||||||
|
return reportDisplay.report != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReportDate(Context context) {
|
||||||
|
String reportDate = "";
|
||||||
|
if(reportDisplay.report == null)
|
||||||
|
return reportDate;
|
||||||
|
|
||||||
|
|
||||||
|
DateFormat dateFormat = SimpleDateFormat.getDateInstance(DateFormat.LONG);
|
||||||
|
reportDate = context.getString(R.string.created_date)+" "+dateFormat.format(reportDisplay.report.creationDate.getTime());
|
||||||
|
if (reportDisplay.report.creationDate.getTime().compareTo(reportDisplay.report.updateDate.getTime())!=0)
|
||||||
|
reportDate += " "+context.getString(R.string.and_updated)+" "+dateFormat.format(reportDisplay.report.updateDate.getTime())+".";
|
||||||
|
return reportDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeSignatureInfo(Context context) {
|
||||||
|
if(reportDisplay.trackers != null && reportDisplay.trackers.size() > 0)
|
||||||
|
return context.getString(R.string.code_signature_found);
|
||||||
|
else if(reportDisplay.trackers != null)
|
||||||
|
return context.getString(R.string.code_signature_not_found);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodePermissionInfo(Context context) {
|
||||||
|
if(reportDisplay.permissions != null && reportDisplay.permissions.size() > 0)
|
||||||
|
return context.getString(R.string.code_permission_found);
|
||||||
|
else if(reportDisplay.permissions != null)
|
||||||
|
return context.getString(R.string.code_permission_not_found);
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getColor(int number) {
|
||||||
|
if (number == 0)
|
||||||
|
return R.drawable.square_green;
|
||||||
|
else if(number < 5)
|
||||||
|
return R.drawable.square_light_yellow;
|
||||||
|
else
|
||||||
|
return R.drawable.square_light_red;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getSource() {
|
||||||
|
return reportDisplay.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getViewOnStore() {
|
||||||
|
return reportDisplay.viewOnStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.Signature;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
@SuppressLint("PackageManagerGetSignatures")
|
||||||
|
public static String getCertificateSHA1Fingerprint(PackageManager pm, String packageName) {
|
||||||
|
int flags = PackageManager.GET_SIGNATURES;
|
||||||
|
PackageInfo packageInfo = null;
|
||||||
|
try {
|
||||||
|
packageInfo = pm.getPackageInfo(packageName, flags);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
assert packageInfo != null;
|
||||||
|
Signature[] signatures = packageInfo.signatures;
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(packageName);
|
||||||
|
|
||||||
|
|
||||||
|
for(Signature signature: signatures) {
|
||||||
|
InputStream input = new ByteArrayInputStream(signature.toByteArray());
|
||||||
|
CertificateFactory cf = null;
|
||||||
|
try {
|
||||||
|
cf = CertificateFactory.getInstance("X509");
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert cf != null;
|
||||||
|
X509Certificate c = (X509Certificate) cf.generateCertificate(input);
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||||
|
byte[] publicKey = md.digest(c.getEncoded());
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(byte2HexFormatted(publicKey).toUpperCase());
|
||||||
|
} catch (NoSuchAlgorithmException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String hexString = null;
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||||
|
byte[] publicKey = md.digest(builder.toString().getBytes());
|
||||||
|
hexString = byte2HexFormatted(publicKey);
|
||||||
|
} catch (NoSuchAlgorithmException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
assert hexString != null;
|
||||||
|
return hexString.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String byte2HexFormatted(byte[] arr) {
|
||||||
|
StringBuilder str = new StringBuilder(arr.length * 2);
|
||||||
|
for (byte anArr : arr) {
|
||||||
|
String h = Integer.toHexString(anArr);
|
||||||
|
int l = h.length();
|
||||||
|
if (l == 1) h = "0" + h;
|
||||||
|
if (l > 2) h = h.substring(l - 2, l);
|
||||||
|
str.append(h.toUpperCase());
|
||||||
|
}
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Simple and not complete markdownToHtml converter
|
||||||
|
*/
|
||||||
|
public static String markdownToHtml(String markdown) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
String[] lines = markdown.split("\r\n");
|
||||||
|
ArrayList<String> listStarter = new ArrayList<>();
|
||||||
|
ArrayList<String> formatStarter = new ArrayList<>();
|
||||||
|
ArrayList<String> closeTags = new ArrayList<>();
|
||||||
|
for(String line : lines) {
|
||||||
|
if (line.matches("^#{1,5} .*")) {
|
||||||
|
int nb = line.indexOf(" ");
|
||||||
|
String hx = "<h"+nb+">";
|
||||||
|
String endhx = "</h"+nb+">";
|
||||||
|
builder.append(hx);
|
||||||
|
closeTags.add(endhx);
|
||||||
|
line = line.substring(line.indexOf(" ")+1);
|
||||||
|
} else if (line.matches("^ *[+\\-*] .*")) {
|
||||||
|
String starter="";
|
||||||
|
if (listStarter.size() > 0 && line.startsWith(listStarter.get(listStarter.size()-1))) {
|
||||||
|
starter = listStarter.get(listStarter.size()-1);
|
||||||
|
} else {
|
||||||
|
Pattern pattern = Pattern.compile("^( *[+\\-*] )");
|
||||||
|
Matcher matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
starter = matcher.group(1);
|
||||||
|
listStarter.add(starter);
|
||||||
|
builder.append("<ul>\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append("<li> ");
|
||||||
|
int beginIndex = line.indexOf(starter)+starter.length();
|
||||||
|
line = line.substring(beginIndex);
|
||||||
|
closeTags.add("</li>");
|
||||||
|
} else {
|
||||||
|
while(!listStarter.isEmpty()) {
|
||||||
|
listStarter.remove(listStarter.size() - 1);
|
||||||
|
builder.append("</ul>\n");
|
||||||
|
}
|
||||||
|
builder.append("<p>");
|
||||||
|
closeTags.add("</p>");
|
||||||
|
}
|
||||||
|
while(!line.isEmpty()){
|
||||||
|
Pattern pattern = Pattern.compile("^\\[(.+?)(?=\\]\\()\\]\\((http.+?)(?=\\))\\)");
|
||||||
|
//Pattern pattern = Pattern.compile("^\\[(.*)\\]\\((http.*)\\)");
|
||||||
|
Matcher matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
builder.append("<a href=\"");
|
||||||
|
builder.append(matcher.group(2));
|
||||||
|
builder.append("\">");
|
||||||
|
builder.append(matcher.group(1));
|
||||||
|
builder.append("</a>");
|
||||||
|
line = line.substring(line.indexOf(")")+1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pattern = Pattern.compile("^(http.*)");
|
||||||
|
matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
builder.append("<a href=\"");
|
||||||
|
builder.append(matcher.group(1));
|
||||||
|
builder.append("\">");
|
||||||
|
builder.append(matcher.group(1));
|
||||||
|
builder.append("</a>");
|
||||||
|
line = line.substring(matcher.group(1).length());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pattern = Pattern.compile("^[*_]{2}(.+)[*_]{2}");
|
||||||
|
matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
if(line.startsWith("*")) {
|
||||||
|
line = line.replaceFirst("\\*\\*", "<b>");
|
||||||
|
formatStarter.add("**");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line = line.replaceFirst("__", "<b>");
|
||||||
|
formatStarter.add("__");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pattern = Pattern.compile("^[*_]{1}(.+)");
|
||||||
|
matcher = pattern.matcher(line);
|
||||||
|
if (matcher.find()) {
|
||||||
|
if(line.startsWith("*")) {
|
||||||
|
line = line.replaceFirst("\\*", "<i>");
|
||||||
|
formatStarter.add("*");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line = line.replaceFirst("_", "<i>");
|
||||||
|
formatStarter.add("_");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(formatStarter.size() > 0) {
|
||||||
|
String checkFormat;
|
||||||
|
if(line.contains(" "))
|
||||||
|
checkFormat = line.substring(0,line.indexOf(" "));
|
||||||
|
else
|
||||||
|
checkFormat = line;
|
||||||
|
String lastFormat = formatStarter.get(formatStarter.size()-1);
|
||||||
|
if (checkFormat.contains(lastFormat)) {
|
||||||
|
if(lastFormat.length()==2) {
|
||||||
|
if (lastFormat.contains("*"))
|
||||||
|
line = line.replaceFirst("\\*\\*", "</b>");
|
||||||
|
else
|
||||||
|
line = line.replaceFirst("__", "</b>");
|
||||||
|
} else {
|
||||||
|
if (lastFormat.contains("*"))
|
||||||
|
line = line.replaceFirst("\\*", "</i>");
|
||||||
|
else
|
||||||
|
line = line.replaceFirst("_", "</i>");
|
||||||
|
}
|
||||||
|
formatStarter.remove(formatStarter.size()-1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.contains(" ")) {
|
||||||
|
builder.append(line.substring(0, line.indexOf(" ") + 1));
|
||||||
|
line = line.substring(line.indexOf(" ") + 1);
|
||||||
|
} else {
|
||||||
|
builder.append(line);
|
||||||
|
line = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//close all unclosed tags starting at the end
|
||||||
|
while(!closeTags.isEmpty()) {
|
||||||
|
builder.append(closeTags.remove(closeTags.size()-1));
|
||||||
|
}
|
||||||
|
builder.append("\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
while(!listStarter.isEmpty()) {
|
||||||
|
listStarter.remove(listStarter.size() - 1);
|
||||||
|
builder.append("</ul>\n");
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,19 +19,20 @@
|
||||||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
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.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.databinding.AppItemBinding;
|
import org.eu.exodus_privacy.exodusprivacy.databinding.AppItemBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
import org.eu.exodus_privacy.exodusprivacy.fragments.AppListFragment;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -41,49 +42,36 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class ApplicationListAdapter extends RecyclerView.Adapter {
|
public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||||
|
|
||||||
private List<PackageInfo> packages;
|
private List<ApplicationViewModel> applicationViewModels;
|
||||||
private PackageManager packageManager;
|
|
||||||
private OnAppClickListener onAppClickListener;
|
private OnAppClickListener onAppClickListener;
|
||||||
private static final String gStore = "com.android.vending";
|
private Object filter = "";
|
||||||
private String filter = "";
|
private AppListFragment.Type filterType = AppListFragment.Type.NAME;
|
||||||
private final int HIDDEN_APP = 0;
|
private final int HIDDEN_APP = 0;
|
||||||
private final int DISPLAYED_APP = 1;
|
private final int DISPLAYED_APP = 1;
|
||||||
|
private int displayedApp = 0;
|
||||||
|
|
||||||
|
private Comparator<ApplicationViewModel> alphaPackageComparator = new Comparator<ApplicationViewModel>() {
|
||||||
private Comparator<PackageInfo> alphaPackageComparator = new Comparator<PackageInfo>() {
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(PackageInfo pack1, PackageInfo pack2) {
|
public int compare(ApplicationViewModel app1, ApplicationViewModel app2) {
|
||||||
String pkg1 = packageManager.getApplicationLabel(pack1.applicationInfo).toString();
|
if(app1.label != null && app2.label != null)
|
||||||
String pkg2 = packageManager.getApplicationLabel(pack2.applicationInfo).toString();
|
return app1.label.toString().compareToIgnoreCase(app2.label.toString());
|
||||||
return pkg1.compareToIgnoreCase(pkg2);
|
else if(app2.label != null)
|
||||||
|
return -1;
|
||||||
|
else if(app1.label != null)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public ApplicationListAdapter(PackageManager manager, OnAppClickListener listener) {
|
public ApplicationListAdapter(Context context, OnAppClickListener listener) {
|
||||||
|
applicationViewModels = new ArrayList<>();
|
||||||
onAppClickListener = listener;
|
onAppClickListener = listener;
|
||||||
setPackageManager(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInstalledPackages(List<PackageInfo> installedPackages) {
|
|
||||||
packages = installedPackages;
|
|
||||||
applyStoreFilter();
|
|
||||||
Collections.sort(packages, alphaPackageComparator);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyStoreFilter() {
|
|
||||||
List<PackageInfo> toRemove = new ArrayList<>();
|
|
||||||
for (PackageInfo pkg : packages) {
|
|
||||||
if (!gStore.equals(packageManager.getInstallerPackageName(pkg.packageName))) {
|
|
||||||
toRemove.add(pkg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packages.removeAll(toRemove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position){
|
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;
|
return applicationViewModels.get(position).isVisible ? DISPLAYED_APP : HIDDEN_APP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -100,12 +88,13 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
if( viewHolder.getItemViewType() == DISPLAYED_APP) {
|
if( viewHolder.getItemViewType() == DISPLAYED_APP) {
|
||||||
final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder;
|
final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder;
|
||||||
holder.setData(packages.get(position));
|
ApplicationViewModel vm = applicationViewModels.get(position);
|
||||||
|
holder.setViewModel(vm);
|
||||||
//noinspection Convert2Lambda
|
//noinspection Convert2Lambda
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
onAppClickListener.onAppClick(holder.packageInfo);
|
onAppClickListener.onAppClick(vm);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}else {
|
}else {
|
||||||
|
@ -115,30 +104,30 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return packages.size();
|
return applicationViewModels.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageManager(PackageManager manager) {
|
public void displayAppList(List<ApplicationViewModel> applications) {
|
||||||
packageManager = manager;
|
applicationViewModels = applications;
|
||||||
if(packageManager != null) {
|
Collections.sort(applicationViewModels, alphaPackageComparator);
|
||||||
List<PackageInfo> installedPackages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
filter(filterType,filter);
|
||||||
setInstalledPackages(installedPackages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{
|
public int getDisplayedApps() {
|
||||||
|
return displayedApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{
|
||||||
ApplicationEmptyViewHolder(View itemView) {
|
ApplicationEmptyViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ApplicationListViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
class ApplicationListViewHolder extends RecyclerView.ViewHolder {
|
ApplicationViewModel viewModel;
|
||||||
|
|
||||||
PackageInfo packageInfo;
|
|
||||||
AppItemBinding appItemBinding;
|
AppItemBinding appItemBinding;
|
||||||
|
|
||||||
ApplicationListViewHolder(AppItemBinding binding) {
|
ApplicationListViewHolder(AppItemBinding binding) {
|
||||||
|
@ -146,8 +135,8 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||||
appItemBinding = binding;
|
appItemBinding = binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(PackageInfo data) {
|
void setViewModel(ApplicationViewModel vm) {
|
||||||
packageInfo = data;
|
viewModel = vm;
|
||||||
|
|
||||||
Context context = appItemBinding.getRoot().getContext();
|
Context context = appItemBinding.getRoot().getContext();
|
||||||
|
|
||||||
|
@ -155,49 +144,90 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||||
appItemBinding.otherVersion.setVisibility(View.GONE);
|
appItemBinding.otherVersion.setVisibility(View.GONE);
|
||||||
appItemBinding.analysed.setVisibility(View.GONE);
|
appItemBinding.analysed.setVisibility(View.GONE);
|
||||||
appItemBinding.appTrackerNb.setVisibility(View.VISIBLE);
|
appItemBinding.appTrackerNb.setVisibility(View.VISIBLE);
|
||||||
|
appItemBinding.appTracker.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
String versionName = viewModel.versionName;
|
||||||
|
long versionCode = viewModel.versionCode;
|
||||||
|
|
||||||
String packageName = packageInfo.packageName;
|
appItemBinding.appLogo.setImageDrawable(viewModel.icon);
|
||||||
String versionName = packageInfo.versionName;
|
|
||||||
|
|
||||||
//get logo
|
appItemBinding.appName.setText(viewModel.label);
|
||||||
try {
|
appItemBinding.source.setText(context.getString(R.string.source,viewModel.source));
|
||||||
appItemBinding.appLogo.setImageDrawable(packageManager.getApplicationIcon(packageName));
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
//get name
|
|
||||||
appItemBinding.appName.setText(packageManager.getApplicationLabel(packageInfo.applicationInfo));
|
|
||||||
|
|
||||||
//get permissions
|
long size = viewModel.requestedPermissions != null ? viewModel.requestedPermissions.length : 0;
|
||||||
if(packageInfo.requestedPermissions != null) {
|
appItemBinding.appPermissionNb.setText(String.valueOf(size));
|
||||||
appItemBinding.appPermissionNb.setText(context.getString(R.string.permissions) + " " + String.valueOf(data.requestedPermissions.length));
|
if(size == 0)
|
||||||
} else {
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_green);
|
||||||
appItemBinding.appPermissionNb.setText(context.getString(R.string.permissions) + " " + String.valueOf(0));
|
else if (size < 5)
|
||||||
}
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_light_yellow);
|
||||||
//get reports
|
else
|
||||||
Report report = DatabaseManager.getInstance(context).getReportFor(packageName, versionName);
|
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_light_red);
|
||||||
|
|
||||||
|
Report report = viewModel.report;
|
||||||
if(report != null) {
|
if(report != null) {
|
||||||
Set<Tracker> trackers = DatabaseManager.getInstance(context).getTrackers(report.trackers);
|
Set<Tracker> trackers = viewModel.trackers;
|
||||||
appItemBinding.appTrackerNb.setText(context.getString(R.string.trackers) + " " + trackers.size());
|
|
||||||
if(!report.version.equals(data.versionName)) {
|
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_light_yellow);
|
||||||
|
else
|
||||||
|
appItemBinding.appTrackerNb.setBackgroundResource(R.drawable.square_light_red);
|
||||||
|
|
||||||
|
if(versionName != null && !report.version.equals(viewModel.versionName)) {
|
||||||
|
String string = context.getString(R.string.tested,versionName, report.version);
|
||||||
|
appItemBinding.otherVersion.setText(string);
|
||||||
|
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
||||||
|
} else if (versionName == null && report.versionCode != versionCode) {
|
||||||
|
String string = context.getString(R.string.tested,String.valueOf(versionCode),String.valueOf(report.versionCode));
|
||||||
|
appItemBinding.otherVersion.setText(string);
|
||||||
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
appItemBinding.appTrackerNb.setVisibility(View.GONE);
|
appItemBinding.appTrackerNb.setVisibility(View.GONE);
|
||||||
|
appItemBinding.appTracker.setVisibility(View.GONE);
|
||||||
appItemBinding.analysed.setVisibility(View.VISIBLE);
|
appItemBinding.analysed.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface OnAppClickListener {
|
public interface OnAppClickListener {
|
||||||
void onAppClick(PackageInfo packageInfo);
|
void onAppClick(ApplicationViewModel vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void filter(AppListFragment.Type type, Object filterObject) {
|
||||||
|
displayedApp = 0;
|
||||||
|
if (type.equals(AppListFragment.Type.NAME)) {
|
||||||
|
filter = filterObject;
|
||||||
|
filterType = type;
|
||||||
|
String filterStr = (String) filterObject;
|
||||||
|
|
||||||
public void filter(String text) {
|
Pattern p = Pattern.compile(Pattern.quote(filterStr.trim()), Pattern.CASE_INSENSITIVE);
|
||||||
filter = text;
|
for (ApplicationViewModel app : applicationViewModels) {
|
||||||
|
app.isVisible = p.matcher(app.label).find();
|
||||||
|
if(app.isVisible)
|
||||||
|
displayedApp++;
|
||||||
|
}
|
||||||
|
} else if(type.equals(AppListFragment.Type.TRACKER)) {
|
||||||
|
filter = filterObject;
|
||||||
|
filterType = type;
|
||||||
|
Long filterLng = (Long) filterObject;
|
||||||
|
|
||||||
|
for (ApplicationViewModel app : applicationViewModels) {
|
||||||
|
app.isVisible = false;
|
||||||
|
if (app.trackers != null) {
|
||||||
|
for (Tracker tracker : app.trackers) {
|
||||||
|
if (tracker.id == filterLng) {
|
||||||
|
app.isVisible = true;
|
||||||
|
displayedApp++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import androidx.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;
|
||||||
|
public String source;
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||||
|
|
||||||
import android.databinding.DataBindingUtil;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.databinding.PermissionItemBinding;
|
import org.eu.exodus_privacy.exodusprivacy.databinding.PermissionItemBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Permission;
|
import org.eu.exodus_privacy.exodusprivacy.objects.Permission;
|
||||||
|
@ -39,7 +40,7 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
if(permissionList == null || permissionList.size() == 0)
|
if(permissionList == null || permissionList.size() == 0)
|
||||||
return 1;
|
return 0;
|
||||||
else
|
else
|
||||||
return permissionList.size();
|
return permissionList.size();
|
||||||
}
|
}
|
||||||
|
@ -60,8 +61,21 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
||||||
|
|
||||||
void setupData(Permission permission) {
|
void setupData(Permission permission) {
|
||||||
if(permission != null) {
|
if(permission != null) {
|
||||||
permissionItemBinding.permissionName.setText(permission.name);
|
if(permission.name != null) {
|
||||||
|
permissionItemBinding.permissionShort.setText(permission.name);
|
||||||
|
permissionItemBinding.permissionShort.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
permissionItemBinding.permissionShort.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
permissionItemBinding.permissionName.setText(permission.fullName.substring(permission.fullName.lastIndexOf(".")+1));
|
||||||
permissionItemBinding.permissionDescription.setText(permission.description);
|
permissionItemBinding.permissionDescription.setText(permission.description);
|
||||||
|
if(permission.icon != null)
|
||||||
|
permissionItemBinding.icon.setImageDrawable(permission.icon);
|
||||||
|
if(!permission.dangerous)
|
||||||
|
permissionItemBinding.dangerous.setVisibility(View.GONE);
|
||||||
|
else
|
||||||
|
permissionItemBinding.dangerous.setVisibility(View.VISIBLE);
|
||||||
manageExpanded(permission);
|
manageExpanded(permission);
|
||||||
permissionItemBinding.mainLayout.setOnClickListener((View.OnClickListener) v -> {
|
permissionItemBinding.mainLayout.setOnClickListener((View.OnClickListener) v -> {
|
||||||
if( permission.description != null && permission.description.trim().length() > 0) {
|
if( permission.description != null && permission.description.trim().length() > 0) {
|
||||||
|
@ -74,6 +88,9 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
||||||
else {
|
else {
|
||||||
permissionItemBinding.permissionName.setText(R.string.no_permissions);
|
permissionItemBinding.permissionName.setText(R.string.no_permissions);
|
||||||
permissionItemBinding.arrow.setText(" ");
|
permissionItemBinding.arrow.setText(" ");
|
||||||
|
permissionItemBinding.permissionShort.setVisibility(View.GONE);
|
||||||
|
permissionItemBinding.dangerous.setVisibility(View.GONE);
|
||||||
|
permissionItemBinding.permissionDescription.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -86,7 +103,7 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
||||||
if( permission.description != null && permission.description.trim().length() > 0 )
|
if( permission.description != null && permission.description.trim().length() > 0 )
|
||||||
permissionItemBinding.arrow.setText("▶");
|
permissionItemBinding.arrow.setText("▶");
|
||||||
else
|
else
|
||||||
permissionItemBinding.arrow.setText("■");
|
permissionItemBinding.arrow.setText("");
|
||||||
permissionItemBinding.permissionDescription.setVisibility(View.GONE);
|
permissionItemBinding.permissionDescription.setVisibility(View.GONE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||||
|
|
||||||
import android.databinding.DataBindingUtil;
|
import android.content.Intent;
|
||||||
import android.databinding.ViewDataBinding;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.databinding.TrackerItemBinding;
|
import org.eu.exodus_privacy.exodusprivacy.databinding.TrackerItemBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class TrackerListAdapter extends android.support.v7.widget.RecyclerView.Adapter<TrackerListAdapter.TrackerListViewHolder>{
|
public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.TrackerListViewHolder>{
|
||||||
|
|
||||||
private Set<Tracker> trackersList;
|
private List<Tracker> trackersList;
|
||||||
|
private OnTrackerClickListener trackerClickListener;
|
||||||
private int layout;
|
private int layout;
|
||||||
|
|
||||||
public TrackerListAdapter(Set<Tracker> trackerList, int resource) {
|
public TrackerListAdapter(Set<Tracker> trackerList, int resource, OnTrackerClickListener listener) {
|
||||||
setTrackers(trackerList);
|
setTrackers(trackerList);
|
||||||
layout = resource;
|
layout = resource;
|
||||||
|
trackerClickListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -35,7 +44,7 @@ public class TrackerListAdapter extends android.support.v7.widget.RecyclerView.A
|
||||||
if(trackersList == null || trackersList.size() == 0)
|
if(trackersList == null || trackersList.size() == 0)
|
||||||
holder.setupData(null);
|
holder.setupData(null);
|
||||||
else
|
else
|
||||||
holder.setupData((Tracker) trackersList.toArray()[position]);
|
holder.setupData(trackersList.get(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,8 +55,13 @@ public class TrackerListAdapter extends android.support.v7.widget.RecyclerView.A
|
||||||
return trackersList.size();
|
return trackersList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Comparator<Tracker> alphaTrackerComparator = (track1, track2) -> track1.name.compareToIgnoreCase(track2.name);
|
||||||
|
|
||||||
public void setTrackers(Set<Tracker> trackers) {
|
public void setTrackers(Set<Tracker> trackers) {
|
||||||
trackersList = trackers;
|
if(trackers != null) {
|
||||||
|
trackersList = new ArrayList<>(trackers);
|
||||||
|
Collections.sort(trackersList, alphaTrackerComparator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
@ -62,13 +76,21 @@ public class TrackerListAdapter extends android.support.v7.widget.RecyclerView.A
|
||||||
void setupData(Tracker tracker) {
|
void setupData(Tracker tracker) {
|
||||||
if(viewDataBinding instanceof TrackerItemBinding) {
|
if(viewDataBinding instanceof TrackerItemBinding) {
|
||||||
TrackerItemBinding binding = (TrackerItemBinding) viewDataBinding;
|
TrackerItemBinding binding = (TrackerItemBinding) viewDataBinding;
|
||||||
if(tracker != null)
|
if(tracker != null) {
|
||||||
binding.trackerName.setText(tracker.name);
|
binding.trackerName.setText(tracker.name + " ➤");
|
||||||
|
binding.getRoot().setOnClickListener(v -> {
|
||||||
|
trackerClickListener.onTrackerClick(tracker.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
else
|
else
|
||||||
binding.trackerName.setText(R.string.no_trackers);
|
binding.trackerName.setText(R.string.no_trackers);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface OnTrackerClickListener{
|
||||||
|
public void onTrackerClick(long trackerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,178 +1,104 @@
|
||||||
/*
|
|
||||||
* 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.fragments;
|
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.databinding.DataBindingUtil;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
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.databinding.ApplistBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.manager.NetworkManager;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AppListFragment extends Fragment {
|
public class AppListFragment extends Fragment {
|
||||||
|
|
||||||
|
|
||||||
private PackageManager packageManager;
|
|
||||||
private NetworkListener networkListener;
|
|
||||||
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
|
||||||
private boolean startupRefresh;
|
|
||||||
private ApplistBinding applistBinding;
|
private ApplistBinding applistBinding;
|
||||||
|
private List<ApplicationViewModel> applications;
|
||||||
private ApplicationListAdapter adapter;
|
private ApplicationListAdapter adapter;
|
||||||
|
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||||
public static AppListFragment newInstance(NetworkListener networkListener, ApplicationListAdapter.OnAppClickListener appClickListener) {
|
private Type filterType = Type.NAME;
|
||||||
AppListFragment fragment = new AppListFragment();
|
private Object filterObject = "";
|
||||||
fragment.setNetworkListener(networkListener);
|
private boolean scrollbarEnabled = true;
|
||||||
fragment.setOnAppClickListener(appClickListener);
|
|
||||||
fragment.startupRefresh = true;
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
//create binding
|
||||||
}
|
applistBinding = DataBindingUtil.inflate(inflater, R.layout.applist,container,false);
|
||||||
|
//init variables
|
||||||
@Override
|
if (applications == null)
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
applications = new ArrayList<>();
|
||||||
applistBinding = DataBindingUtil.inflate(inflater,R.layout.applist,container,false);
|
Context context = applistBinding.getRoot().getContext();
|
||||||
|
//configure list
|
||||||
|
applistBinding.appList.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
applistBinding.appList.setVerticalScrollBarEnabled(scrollbarEnabled);
|
||||||
|
adapter = new ApplicationListAdapter(context, onAppClickListener);
|
||||||
|
adapter.displayAppList(applications);
|
||||||
|
adapter.filter(filterType,filterObject);
|
||||||
|
applistBinding.appList.setAdapter(adapter);
|
||||||
return applistBinding.getRoot();
|
return applistBinding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener listener){
|
||||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
onAppClickListener = listener;
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
if(applistBinding == null)
|
|
||||||
return;
|
|
||||||
Context context = applistBinding.getRoot().getContext();
|
|
||||||
applistBinding.swipeRefresh.setOnRefreshListener(() -> startRefresh());
|
|
||||||
if (packageManager == null)
|
|
||||||
packageManager = context.getPackageManager();
|
|
||||||
|
|
||||||
applistBinding.appList.setLayoutManager(new LinearLayoutManager(context));
|
|
||||||
if (packageManager != null) {
|
|
||||||
if(startupRefresh) {
|
|
||||||
startRefresh();
|
|
||||||
startupRefresh = false;
|
|
||||||
}
|
|
||||||
applistBinding.noPackageManager.setVisibility(View.GONE);
|
|
||||||
applistBinding.noAppFound.setVisibility(View.GONE);
|
|
||||||
adapter = new ApplicationListAdapter(packageManager, onAppClickListener);
|
|
||||||
if(adapter.getItemCount() == 0) {
|
|
||||||
applistBinding.noAppFound.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
applistBinding.appList.setAdapter(adapter);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
applistBinding.noPackageManager.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startRefresh(){
|
public void setApplications(List<ApplicationViewModel> applicationList){
|
||||||
if(applistBinding == null)
|
applications = applicationList;
|
||||||
return;
|
if(adapter != null)
|
||||||
applistBinding.layoutProgress.setVisibility(View.VISIBLE);
|
adapter.displayAppList(applications);
|
||||||
applistBinding.swipeRefresh.setRefreshing(true);
|
|
||||||
List<PackageInfo> packageInstalled = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
|
||||||
ArrayList<String> packageList = new ArrayList<>();
|
|
||||||
for(PackageInfo pkgInfo : packageInstalled)
|
|
||||||
packageList.add(pkgInfo.packageName);
|
|
||||||
|
|
||||||
NetworkManager.getInstance().getReports(applistBinding.getRoot().getContext(),networkListener,packageList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateComplete() {
|
public void setFilter(Type type, Object filter){
|
||||||
if(applistBinding != null) {
|
filterType = type;
|
||||||
applistBinding.layoutProgress.setVisibility(View.GONE);
|
filterObject = filter;
|
||||||
applistBinding.swipeRefresh.setRefreshing(false);
|
if(adapter != null)
|
||||||
if(packageManager != null && applistBinding.appList.getAdapter() != null) {
|
adapter.filter(type,filterObject);
|
||||||
((ApplicationListAdapter) applistBinding.appList.getAdapter()).setPackageManager(packageManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNetworkListener(NetworkListener listener) {
|
public void disableScrollBar() {
|
||||||
this.networkListener = new NetworkListener() {
|
scrollbarEnabled = false;
|
||||||
@Override
|
if (applistBinding != null)
|
||||||
public void onSuccess() {
|
applistBinding.appList.setVerticalScrollBarEnabled(false);
|
||||||
listener.onSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String error) {
|
|
||||||
listener.onError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onProgress(int resourceId, int progress, int maxProgress) {
|
|
||||||
updateProgress(resourceId, progress, maxProgress);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateProgress(int resourceId, int progress, int maxProgress) {
|
public void enableScrollBar() {
|
||||||
Activity activity = getActivity();
|
scrollbarEnabled = true;
|
||||||
if(activity == null)
|
if (applistBinding != null)
|
||||||
return;
|
applistBinding.appList.setVerticalScrollBarEnabled(true);
|
||||||
activity.runOnUiThread(() -> {
|
|
||||||
if (applistBinding == null)
|
|
||||||
return;
|
|
||||||
if(maxProgress > 0)
|
|
||||||
applistBinding.statusProgress.setText(getString(resourceId)+" "+progress+"/"+maxProgress);
|
|
||||||
else
|
|
||||||
applistBinding.statusProgress.setText(getString(resourceId));
|
|
||||||
applistBinding.progress.setMax(maxProgress);
|
|
||||||
applistBinding.progress.setProgress(progress);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener onAppClickListener) {
|
public int getTotalApps() {
|
||||||
this.onAppClickListener = onAppClickListener;
|
if (adapter == null)
|
||||||
|
return 0;
|
||||||
|
return adapter.getItemCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int getDisplayedApps() {
|
||||||
public void onAttach(Context context) {
|
if (adapter == null)
|
||||||
super.onAttach(context);
|
return 0;
|
||||||
packageManager = context.getPackageManager();
|
return adapter.getDisplayedApps();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public enum Type {
|
||||||
public void onDetach() {
|
NAME,
|
||||||
super.onDetach();
|
TRACKER
|
||||||
packageManager = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void filter(String filter){
|
public enum Order {
|
||||||
adapter.filter(filter);
|
NAME_ASC,
|
||||||
|
NAME_DSC,
|
||||||
|
TRACKER_ASC,
|
||||||
|
TRACKER_DSC,
|
||||||
|
PERMISSIONS_ASC,
|
||||||
|
PERMISSIONS_DSC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
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;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class ComputeAppListTask extends AsyncTask<Void, Void, List<ApplicationViewModel>> {
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
void onAppsComputed(List<ApplicationViewModel> apps);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String gStore = "com.android.vending";
|
||||||
|
private static final String fdroid = "ord.fdroid.fdroid";
|
||||||
|
|
||||||
|
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);
|
||||||
|
vms = applyStoreFilter(installedPackages, databaseManager, packageManager);
|
||||||
|
convertPackagesToViewModels(vms, databaseManager, packageManager);
|
||||||
|
}
|
||||||
|
return vms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(List<ApplicationViewModel> vms) {
|
||||||
|
Listener listener = listenerRef.get();
|
||||||
|
|
||||||
|
if(listener != null) {
|
||||||
|
listener.onAppsComputed(vms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertPackagesToViewModels(List<ApplicationViewModel> appsToBuild,
|
||||||
|
DatabaseManager databaseManager,
|
||||||
|
PackageManager packageManager) {
|
||||||
|
for (ApplicationViewModel vm : appsToBuild) {
|
||||||
|
try {
|
||||||
|
PackageInfo pi = packageManager.getPackageInfo(vm.packageName, PackageManager.GET_PERMISSIONS);
|
||||||
|
buildViewModelFromPackageInfo(vm, pi, databaseManager, packageManager);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildViewModelFromPackageInfo(ApplicationViewModel vm, PackageInfo pi,
|
||||||
|
DatabaseManager databaseManager,
|
||||||
|
PackageManager packageManager) {
|
||||||
|
|
||||||
|
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, vm.source);
|
||||||
|
else {
|
||||||
|
vm.report = databaseManager.getReportFor(vm.packageName, vm.versionCode, vm.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ApplicationViewModel> applyStoreFilter(List<PackageInfo> packageInfos,
|
||||||
|
DatabaseManager databaseManager,
|
||||||
|
PackageManager packageManager) {
|
||||||
|
List<ApplicationViewModel> result = new ArrayList<>();
|
||||||
|
for (PackageInfo packageInfo : packageInfos) {
|
||||||
|
String packageName = packageInfo.packageName;
|
||||||
|
String installerPackageName = packageManager.getInstallerPackageName(packageName);
|
||||||
|
ApplicationViewModel vm = new ApplicationViewModel();
|
||||||
|
vm.packageName = packageName;
|
||||||
|
if (!gStore.equals(installerPackageName) && !fdroid.equals(installerPackageName)) {
|
||||||
|
String auid = Utils.getCertificateSHA1Fingerprint(packageManager, packageName);
|
||||||
|
Map<String,String> sources = databaseManager.getSources(packageName);
|
||||||
|
for(Map.Entry<String,String> entry : sources.entrySet()) {
|
||||||
|
if(entry.getValue().equalsIgnoreCase(auid)) {
|
||||||
|
vm.source = entry.getKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (gStore.equals(installerPackageName)) {
|
||||||
|
vm.source = "google";
|
||||||
|
} else {
|
||||||
|
vm.source = "fdroid";
|
||||||
|
}
|
||||||
|
ApplicationInfo appInfo = null;
|
||||||
|
try {
|
||||||
|
appInfo = packageManager.getApplicationInfo(packageName,0);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if(vm.source != null && appInfo != null && appInfo.enabled)
|
||||||
|
result.add(vm);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
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.HomeBinding;
|
||||||
|
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 HomeFragment extends Fragment implements ComputeAppListTask.Listener, Updatable {
|
||||||
|
|
||||||
|
private @Nullable
|
||||||
|
PackageManager packageManager;
|
||||||
|
private NetworkListener networkListener;
|
||||||
|
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||||
|
private boolean startupRefresh = true;
|
||||||
|
private HomeBinding homeBinding;
|
||||||
|
private List<ApplicationViewModel> applications;
|
||||||
|
private AppListFragment appListFragment;
|
||||||
|
private boolean startRefreshAsked;
|
||||||
|
private boolean refreshInProgress;
|
||||||
|
|
||||||
|
private int lastResource=0;
|
||||||
|
private int lastProgress=0;
|
||||||
|
private int lastMaxProgress=0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
if(applications == null)
|
||||||
|
applications = new ArrayList<>();
|
||||||
|
homeBinding = DataBindingUtil.inflate(inflater, R.layout.home,container,false);
|
||||||
|
appListFragment = new AppListFragment();
|
||||||
|
appListFragment.setOnAppClickListener(onAppClickListener);
|
||||||
|
FragmentManager fragmentManager = getChildFragmentManager();
|
||||||
|
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||||
|
transaction.replace(R.id.app_list_container,appListFragment);
|
||||||
|
transaction.commit();
|
||||||
|
Context context = homeBinding.getRoot().getContext();
|
||||||
|
packageManager = context.getPackageManager();
|
||||||
|
homeBinding.swipeRefresh.setOnRefreshListener(this::startRefresh);
|
||||||
|
if(packageManager != null) {
|
||||||
|
homeBinding.noPackageManager.setVisibility(View.GONE);
|
||||||
|
onAppsComputed(applications);
|
||||||
|
if(applications.isEmpty())
|
||||||
|
displayAppListAsync();
|
||||||
|
if(startRefreshAsked)
|
||||||
|
startRefresh();
|
||||||
|
else if (refreshInProgress) {
|
||||||
|
homeBinding.layoutProgress.setVisibility(View.VISIBLE);
|
||||||
|
homeBinding.swipeRefresh.setRefreshing(true);
|
||||||
|
updateProgress(lastResource,lastProgress,lastMaxProgress);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
homeBinding.noPackageManager.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
return homeBinding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startRefresh(){
|
||||||
|
if(packageManager != null) {
|
||||||
|
refreshInProgress = true;
|
||||||
|
homeBinding.layoutProgress.setVisibility(View.VISIBLE);
|
||||||
|
homeBinding.swipeRefresh.setRefreshing(true);
|
||||||
|
List<PackageInfo> packageInstalled = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||||
|
ArrayList<String> packageList = new ArrayList<>();
|
||||||
|
for (PackageInfo pkgInfo : packageInstalled)
|
||||||
|
packageList.add(pkgInfo.packageName);
|
||||||
|
|
||||||
|
NetworkManager.getInstance().getReports(homeBinding.getRoot().getContext(), networkListener, packageList);
|
||||||
|
startRefreshAsked = false;
|
||||||
|
} else {
|
||||||
|
startRefreshAsked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdateComplete() {
|
||||||
|
refreshInProgress = false;
|
||||||
|
homeBinding.layoutProgress.setVisibility(View.GONE);
|
||||||
|
homeBinding.swipeRefresh.setRefreshing(false);
|
||||||
|
displayAppListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkListener(NetworkListener listener) {
|
||||||
|
this.networkListener = new NetworkListener() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
listener.onSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(String error) {
|
||||||
|
listener.onError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onProgress(int resourceId, int progress, int maxProgress) {
|
||||||
|
updateProgress(resourceId, progress, maxProgress);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProgress(int resourceId, int progress, int maxProgress) {
|
||||||
|
lastResource = resourceId;
|
||||||
|
lastProgress = progress;
|
||||||
|
lastMaxProgress = maxProgress;
|
||||||
|
if(lastResource == 0)
|
||||||
|
return;
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if(activity == null)
|
||||||
|
return;
|
||||||
|
activity.runOnUiThread(() -> {
|
||||||
|
if (homeBinding == null)
|
||||||
|
return;
|
||||||
|
if(maxProgress > 0)
|
||||||
|
homeBinding.statusProgress.setText(activity.getString(resourceId)+" "+progress+"/"+maxProgress);//fixme
|
||||||
|
else
|
||||||
|
homeBinding.statusProgress.setText(activity.getString(resourceId));
|
||||||
|
homeBinding.progress.setMax(maxProgress);
|
||||||
|
homeBinding.progress.setProgress(progress);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener onAppClickListener) {
|
||||||
|
this.onAppClickListener = onAppClickListener;
|
||||||
|
if(appListFragment != null)
|
||||||
|
appListFragment.setOnAppClickListener(onAppClickListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void filter(String filter){
|
||||||
|
appListFragment.setFilter(AppListFragment.Type.NAME,filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayAppListAsync() {
|
||||||
|
homeBinding.noAppFound.setVisibility(View.GONE);
|
||||||
|
if (applications.isEmpty()) {
|
||||||
|
homeBinding.retrieveApp.setVisibility(View.VISIBLE);
|
||||||
|
homeBinding.logo.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
new ComputeAppListTask(
|
||||||
|
new WeakReference<>(packageManager),
|
||||||
|
new WeakReference<>(DatabaseManager.getInstance(getActivity())),
|
||||||
|
new WeakReference<>(this)
|
||||||
|
).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppsComputed(List<ApplicationViewModel> apps) {
|
||||||
|
this.applications = apps;
|
||||||
|
homeBinding.retrieveApp.setVisibility(View.GONE);
|
||||||
|
homeBinding.logo.setVisibility(View.GONE);
|
||||||
|
homeBinding.noAppFound.setVisibility(apps.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
|
appListFragment.setApplications(apps);
|
||||||
|
if(!apps.isEmpty()) {
|
||||||
|
if(startupRefresh) {
|
||||||
|
startRefresh();
|
||||||
|
startupRefresh = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,171 +20,154 @@
|
||||||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PermissionInfo;
|
import android.net.Uri;
|
||||||
import android.databinding.DataBindingUtil;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.ReportViewModel;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.adapters.PermissionListAdapter;
|
import org.eu.exodus_privacy.exodusprivacy.adapters.PermissionListAdapter;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.databinding.ReportBinding;
|
import org.eu.exodus_privacy.exodusprivacy.databinding.ReportBinding;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
import org.eu.exodus_privacy.exodusprivacy.objects.ReportDisplay;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Permission;
|
public class ReportFragment extends Fragment implements Updatable {
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ReportFragment extends Fragment {
|
|
||||||
|
|
||||||
private PackageManager packageManager;
|
private PackageManager packageManager;
|
||||||
private PackageInfo packageInfo;
|
private PackageInfo packageInfo = null;
|
||||||
private ReportBinding reportBinding;
|
private ReportBinding reportBinding;
|
||||||
|
private TrackerListAdapter.OnTrackerClickListener trackerClickListener;
|
||||||
|
private ApplicationViewModel model;
|
||||||
|
|
||||||
public static ReportFragment newInstance(PackageManager packageManager, PackageInfo packageInfo) {
|
public static ReportFragment newInstance(PackageManager packageManager,ApplicationViewModel model, PackageInfo packageInfo, TrackerListAdapter.OnTrackerClickListener trackerClickListener) {
|
||||||
ReportFragment fragment = new ReportFragment();
|
ReportFragment fragment = new ReportFragment();
|
||||||
fragment.setPackageManager(packageManager);
|
fragment.setPackageManager(packageManager);
|
||||||
fragment.setPackageInfo(packageInfo);
|
fragment.setPackageInfo(packageInfo);
|
||||||
|
fragment.setApplicationViewModel(model);
|
||||||
|
fragment.setOnTrackerClickListener(trackerClickListener);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setApplicationViewModel(ApplicationViewModel model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if(savedInstanceState != null && packageInfo == null) {
|
||||||
|
packageInfo = savedInstanceState.getParcelable("PackageInfo");
|
||||||
|
}
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
|
outState.putParcelable("PackageInfo", packageInfo);
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
reportBinding = DataBindingUtil.inflate(inflater,R.layout.report,container,false);
|
reportBinding = DataBindingUtil.inflate(inflater,R.layout.report,container,false);
|
||||||
updateComplete();
|
onUpdateComplete();
|
||||||
return reportBinding.getRoot();
|
return reportBinding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateComplete() {
|
@Override
|
||||||
|
public void onUpdateComplete() {
|
||||||
|
if(model != null)
|
||||||
|
onUpdateComplete(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onUpdateComplete(ApplicationViewModel model) {
|
||||||
Context context = reportBinding.getRoot().getContext();
|
Context context = reportBinding.getRoot().getContext();
|
||||||
String packageName = packageInfo.packageName;
|
|
||||||
String versionName = packageInfo.versionName;
|
|
||||||
|
|
||||||
//setup logo
|
ReportDisplay reportDisplay = ReportDisplay.buildReportDisplay(context,model,packageManager,packageInfo);
|
||||||
try {
|
ReportViewModel viewModel = new ReportViewModel();
|
||||||
reportBinding.logo.setImageDrawable(packageManager.getApplicationIcon(packageName));
|
viewModel.setReportDisplay(reportDisplay);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
reportBinding.setReportInfo(viewModel);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
//setup name
|
|
||||||
reportBinding.name.setText(packageManager.getApplicationLabel(packageInfo.applicationInfo));
|
|
||||||
|
|
||||||
//setup permissions number
|
|
||||||
String permissions_text;
|
|
||||||
if (packageInfo.requestedPermissions != null && packageInfo.requestedPermissions.length > 0)
|
|
||||||
permissions_text = context.getString(R.string.permissions) + " " + String.valueOf(packageInfo.requestedPermissions.length);
|
|
||||||
else
|
|
||||||
permissions_text = context.getString(R.string.permissions);
|
|
||||||
|
|
||||||
reportBinding.permissionsTitle.setText(permissions_text);
|
|
||||||
|
|
||||||
//setup permissions list
|
|
||||||
List<Permission> requestedPermissions = null;
|
|
||||||
if (packageInfo.requestedPermissions != null && packageInfo.requestedPermissions.length > 0) {
|
|
||||||
requestedPermissions = new ArrayList<>();
|
|
||||||
for(int i = 0; i < packageInfo.requestedPermissions.length; i++) {
|
|
||||||
Permission permission = new Permission();
|
|
||||||
permission.fullName = packageInfo.requestedPermissions[i];
|
|
||||||
try {
|
|
||||||
PermissionInfo permissionInfo = packageManager.getPermissionInfo(permission.fullName,PackageManager.GET_META_DATA);
|
|
||||||
if(permissionInfo.loadDescription(packageManager) != null)
|
|
||||||
permission.description = permissionInfo.loadDescription(packageManager).toString();
|
|
||||||
if(permissionInfo.loadLabel(packageManager) != null)
|
|
||||||
permission.name = permissionInfo.loadLabel(packageManager).toString();
|
|
||||||
requestedPermissions.add(permission);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reportBinding.permissions.setLayoutManager(new LinearLayoutManager(context));
|
reportBinding.permissions.setLayoutManager(new LinearLayoutManager(context));
|
||||||
PermissionListAdapter permissionAdapter = new PermissionListAdapter(requestedPermissions);
|
PermissionListAdapter permissionAdapter = new PermissionListAdapter(reportDisplay.permissions);
|
||||||
reportBinding.permissions.setNestedScrollingEnabled(false);
|
reportBinding.permissions.setNestedScrollingEnabled(false);
|
||||||
reportBinding.permissions.setAdapter(permissionAdapter);
|
reportBinding.permissions.setAdapter(permissionAdapter);
|
||||||
|
|
||||||
|
|
||||||
reportBinding.analysed.setVisibility(View.GONE);
|
|
||||||
reportBinding.trackerLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
//get trackers
|
|
||||||
Report report = DatabaseManager.getInstance(context).getReportFor(packageName,versionName);
|
|
||||||
Set<Tracker> trackers = null;
|
|
||||||
if(report != null) {
|
|
||||||
trackers = DatabaseManager.getInstance(context).getTrackers(report.trackers);
|
|
||||||
} else {
|
|
||||||
reportBinding.analysed.setVisibility(View.VISIBLE);
|
|
||||||
reportBinding.trackerLayout.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
//setup trackers report
|
|
||||||
String trackers_text;
|
|
||||||
if(trackers != null && trackers.size() > 0)
|
|
||||||
trackers_text = context.getString(R.string.trackers)+" "+String.valueOf(trackers.size());
|
|
||||||
else
|
|
||||||
trackers_text = context.getString(R.string.trackers);
|
|
||||||
reportBinding.trackersTitle.setText(trackers_text);
|
|
||||||
|
|
||||||
//setup trackers lists
|
//setup trackers lists
|
||||||
reportBinding.trackers.setLayoutManager(new LinearLayoutManager(context));
|
reportBinding.trackers.setLayoutManager(new LinearLayoutManager(context));
|
||||||
TrackerListAdapter trackerAdapter = new TrackerListAdapter(trackers,R.layout.tracker_item);
|
TrackerListAdapter trackerAdapter = new TrackerListAdapter(reportDisplay.trackers,R.layout.tracker_item, trackerClickListener);
|
||||||
reportBinding.trackers.setNestedScrollingEnabled(false);
|
reportBinding.trackers.setNestedScrollingEnabled(false);
|
||||||
reportBinding.trackers.setAdapter(trackerAdapter);
|
reportBinding.trackers.setAdapter(trackerAdapter);
|
||||||
|
|
||||||
//setup creator
|
reportBinding.reportDate.setText(viewModel.getReportDate(context));
|
||||||
if(report != null)
|
reportBinding.creatorValue.setText(viewModel.getCreator(context));
|
||||||
reportBinding.creator.setText(DatabaseManager.getInstance(context).getCreator(report.appId));
|
reportBinding.codeSignature.setText(viewModel.getCodeSignatureInfo(context));
|
||||||
else
|
reportBinding.codePermission.setText(viewModel.getCodePermissionInfo(context));
|
||||||
reportBinding.creator.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
//setup installed
|
reportBinding.trackerExplanation.setText(getText(R.string.tracker_infos));
|
||||||
String installed_str = context.getString(R.string.installed) +" "+ versionName;
|
reportBinding.trackerExplanation.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
reportBinding.installedVersion.setText(installed_str);
|
reportBinding.trackerExplanation.setClickable(true);
|
||||||
|
|
||||||
//setup reportversion
|
reportBinding.permissionExplanationDangerous.setText(getText(R.string.permission_infos_dangerous));
|
||||||
reportBinding.reportVersion.setVisibility(View.VISIBLE);
|
reportBinding.permissionExplanationDangerous.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
if(report != null && !report.version.equals(versionName)) {
|
reportBinding.permissionExplanationDangerous.setClickable(true);
|
||||||
String report_str = context.getString(R.string.report_version)+" "+report.version;
|
|
||||||
reportBinding.reportVersion.setText(report_str);
|
reportBinding.permissionExplanation.setText(getText(R.string.permission_infos));
|
||||||
|
reportBinding.permissionExplanation.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
reportBinding.permissionExplanation.setClickable(true);
|
||||||
|
|
||||||
|
reportBinding.viewStore.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
if(reportDisplay.source.contains("google"))
|
||||||
|
intent.setData(Uri.parse("https://play.google.com/store/apps/details?id="+reportDisplay.packageName));
|
||||||
|
else
|
||||||
|
intent.setData(Uri.parse("https://f-droid.org/packages/"+reportDisplay.packageName));
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(reportDisplay.report != null) {
|
||||||
|
reportBinding.reportUrl.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(Uri.parse("https://reports.exodus-privacy.eu.org/reports/" + reportDisplay.report.id + "/"));
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
|
||||||
reportBinding.reportVersion.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
//setup report url
|
|
||||||
if(report != null)
|
|
||||||
reportBinding.reportUrl.setText("https://reports.exodus-privacy.eu.org/reports/"+report.id+"/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageManager(PackageManager packageManager) {
|
private void setPackageManager(PackageManager packageManager) {
|
||||||
this.packageManager = packageManager;
|
this.packageManager = packageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPackageInfo(PackageInfo packageInfo) {
|
private void setPackageInfo(PackageInfo packageInfo) {
|
||||||
this.packageInfo = packageInfo;
|
this.packageInfo = packageInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setOnTrackerClickListener(TrackerListAdapter.OnTrackerClickListener listener) {
|
||||||
|
trackerClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareOptionsMenu(Menu menu) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
MenuItem item = menu.findItem(R.id.action_filter);
|
MenuItem item = menu.findItem(R.id.action_filter);
|
||||||
item.setVisible(false);
|
item.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ApplicationViewModel getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.databinding.TrackerBinding;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TrackerFragment extends Fragment implements ComputeAppListTask.Listener, Updatable {
|
||||||
|
|
||||||
|
private TrackerBinding trackerBinding;
|
||||||
|
private long trackerId;
|
||||||
|
private PackageManager packageManager;
|
||||||
|
private List<ApplicationViewModel> applications;
|
||||||
|
private AppListFragment appListFragment;
|
||||||
|
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||||
|
|
||||||
|
public static TrackerFragment newInstance(long trackerId) {
|
||||||
|
TrackerFragment fragment = new TrackerFragment();
|
||||||
|
fragment.setTrackerId(trackerId);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTrackerId(long id) {
|
||||||
|
trackerId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdateComplete() {
|
||||||
|
Context context = trackerBinding.getRoot().getContext();
|
||||||
|
Tracker tracker = DatabaseManager.getInstance(context).getTracker(trackerId);
|
||||||
|
trackerBinding.name.setText(tracker.name);
|
||||||
|
trackerBinding.codeDetection.setText(tracker.codeSignature);
|
||||||
|
trackerBinding.networkDetection.setText(tracker.networkSignature);
|
||||||
|
trackerBinding.description.setText(Html.fromHtml(Utils.markdownToHtml(tracker.description)));
|
||||||
|
trackerBinding.description.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
trackerBinding.description.setClickable(true);
|
||||||
|
trackerBinding.trackerUrl.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(Uri.parse(tracker.website));
|
||||||
|
startActivity(intent);
|
||||||
|
});
|
||||||
|
displayAppListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
trackerBinding = DataBindingUtil.inflate(inflater, R.layout.tracker,container,false);
|
||||||
|
if (applications == null)
|
||||||
|
applications = new ArrayList<>();
|
||||||
|
appListFragment = new AppListFragment();
|
||||||
|
appListFragment.setFilter(AppListFragment.Type.TRACKER,trackerId);
|
||||||
|
appListFragment.disableScrollBar();
|
||||||
|
appListFragment.setOnAppClickListener(onAppClickListener);
|
||||||
|
FragmentManager manager = getChildFragmentManager();
|
||||||
|
FragmentTransaction transaction = manager.beginTransaction();
|
||||||
|
transaction.replace(R.id.applications,appListFragment);
|
||||||
|
transaction.commit();
|
||||||
|
Context context = trackerBinding.getRoot().getContext();
|
||||||
|
packageManager = context.getPackageManager();
|
||||||
|
onUpdateComplete();
|
||||||
|
return trackerBinding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
|
MenuItem item = menu.findItem(R.id.action_filter);
|
||||||
|
item.setVisible(false);
|
||||||
|
item = menu.findItem(R.id.action_settings);
|
||||||
|
item.setVisible(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayAppListAsync() {
|
||||||
|
trackerBinding.noAppFound.setVisibility(View.GONE);
|
||||||
|
trackerBinding.trackerPresence.setVisibility(View.GONE);
|
||||||
|
//todo
|
||||||
|
trackerBinding.trackerPresenceNb.setVisibility(View.GONE);
|
||||||
|
//todo
|
||||||
|
trackerBinding.trackerPresenceTitle.setVisibility(View.GONE);
|
||||||
|
if (applications.isEmpty()) {
|
||||||
|
trackerBinding.retrieveApp.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
new ComputeAppListTask(
|
||||||
|
new WeakReference<>(packageManager),
|
||||||
|
new WeakReference<>(DatabaseManager.getInstance(getActivity())),
|
||||||
|
new WeakReference<>(this)
|
||||||
|
).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAppsComputed(List<ApplicationViewModel> apps) {
|
||||||
|
this.applications = apps;
|
||||||
|
trackerBinding.retrieveApp.setVisibility(View.GONE);
|
||||||
|
trackerBinding.noAppFound.setVisibility(apps.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
|
trackerBinding.trackerPresence.setVisibility(View.VISIBLE);
|
||||||
|
trackerBinding.trackerPresenceNb.setVisibility(View.VISIBLE);
|
||||||
|
trackerBinding.trackerPresenceTitle.setVisibility(View.VISIBLE);
|
||||||
|
appListFragment.setApplications(apps);
|
||||||
|
int total = appListFragment.getTotalApps();
|
||||||
|
int displayedApps = appListFragment.getDisplayedApps();
|
||||||
|
int percent = displayedApps*100/total;
|
||||||
|
if(percent >=50)
|
||||||
|
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_red);
|
||||||
|
else if(percent >=33)
|
||||||
|
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_dark_orange);
|
||||||
|
else if(percent >=20)
|
||||||
|
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_yellow);
|
||||||
|
else
|
||||||
|
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_light_blue);
|
||||||
|
|
||||||
|
trackerBinding.trackerPresenceNb.setText(percent+"%");
|
||||||
|
Context context = trackerBinding.getRoot().getContext();
|
||||||
|
String presence = context.getResources().getString(R.string.tracker_presence,displayedApps);
|
||||||
|
trackerBinding.trackerPresence.setText(presence);
|
||||||
|
trackerBinding.trackerPresenceTitle.setText(R.string.tracker_presence_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener listener) {
|
||||||
|
onAppClickListener = listener;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||||
|
|
||||||
|
public interface Updatable {
|
||||||
|
void onUpdateComplete();
|
||||||
|
}
|
|
@ -29,8 +29,10 @@ import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class DatabaseManager extends SQLiteOpenHelper {
|
public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
|
@ -44,14 +46,14 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public static DatabaseManager getInstance(Context context) {
|
public static DatabaseManager getInstance(Context context) {
|
||||||
if(instance == null)
|
if(instance == null)
|
||||||
instance = new DatabaseManager(context,"Exodus.db",null,1);
|
instance = new DatabaseManager(context,"Exodus.db",null,3);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
db.execSQL("Create Table if not exists applications (id INTEGER primary key autoincrement, package TEXT, name TEXT, creator TEXT);");
|
db.execSQL("Create Table if not exists applications (id INTEGER primary key autoincrement, package TEXT, name TEXT, creator TEXT, sources TEXT);");
|
||||||
db.execSQL("Create Table if not exists reports (id INTEGER primary key, creation INTEGER, updateat INTEGER, downloads TEXT, version TEXT, version_code INTEGER, app_id INTEGER, foreign key(app_id) references applications(id));");
|
db.execSQL("Create Table if not exists reports (id INTEGER primary key, creation INTEGER, updateat INTEGER, downloads TEXT, version TEXT, version_code INTEGER, app_id INTEGER, source TEXT, foreign key(app_id) references applications(id));");
|
||||||
db.execSQL("Create Table if not exists trackers (id INTEGER primary key, name TEXT, creation_date INTEGER, code_signature TEXT, network_signature TEXT, website TEXT, description TEXT);");
|
db.execSQL("Create Table if not exists trackers (id INTEGER primary key, name TEXT, creation_date INTEGER, code_signature TEXT, network_signature TEXT, website TEXT, description TEXT);");
|
||||||
|
|
||||||
db.execSQL("Create Table if not exists trackers_reports (id INTEGER primary key autoincrement, tracker_id INTEGER, report_id INTEGER, foreign key(tracker_id) references trackers(id), foreign key(report_id) references reports(id));");
|
db.execSQL("Create Table if not exists trackers_reports (id INTEGER primary key autoincrement, tracker_id INTEGER, report_id INTEGER, foreign key(tracker_id) references trackers(id), foreign key(report_id) references reports(id));");
|
||||||
|
@ -59,7 +61,36 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
// do nothing
|
if(oldVersion <= 1) {
|
||||||
|
db.execSQL("Alter Table applications add column auid TEXT");
|
||||||
|
}
|
||||||
|
if (oldVersion <= 2) {
|
||||||
|
try {
|
||||||
|
db.beginTransaction();
|
||||||
|
db.execSQL("Alter Table reports add column source TEXT");
|
||||||
|
db.execSQL("Alter Table applications rename to old_apps");
|
||||||
|
db.execSQL("Create Table if not exists applications (id INTEGER primary key autoincrement, package TEXT, name TEXT, creator TEXT, sources TEXT);");
|
||||||
|
|
||||||
|
Cursor cursor = db.query("old_apps",null,null,null,null,null,null);
|
||||||
|
while (cursor.moveToNext()){
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put("package",cursor.getString(1));
|
||||||
|
values.put("name",cursor.getString(2));
|
||||||
|
values.put("creator",cursor.getString(3));
|
||||||
|
String sources = "unknown:"+cursor.getString(4)+"|";
|
||||||
|
values.put("sources",sources);
|
||||||
|
db.insert("applications",null,values);
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
db.execSQL("Drop Table old_apps");
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean existReport(SQLiteDatabase db, long reportId) {
|
private boolean existReport(SQLiteDatabase db, long reportId) {
|
||||||
|
@ -119,6 +150,7 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
values.put("package", application.packageName);
|
values.put("package", application.packageName);
|
||||||
values.put("name",application.name);
|
values.put("name",application.name);
|
||||||
values.put("creator",application.creator);
|
values.put("creator",application.creator);
|
||||||
|
values.put("sources",buildSourcesStr(application.sources));
|
||||||
|
|
||||||
if(!existApplication(db, application.packageName)) {
|
if(!existApplication(db, application.packageName)) {
|
||||||
db.insert("applications", null, values);
|
db.insert("applications", null, values);
|
||||||
|
@ -134,8 +166,8 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||||
if(cursor.moveToFirst()) {
|
if(cursor.moveToFirst()) {
|
||||||
application.id = cursor.getLong(0);
|
application.id = cursor.getLong(0);
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
for(Report report : application.reports) {
|
for(Report report : application.reports) {
|
||||||
insertOrUpdateReport(db,report,application.id);
|
insertOrUpdateReport(db,report,application.id);
|
||||||
|
@ -151,6 +183,7 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
values.put("version",report.version);
|
values.put("version",report.version);
|
||||||
values.put("version_code",report.versionCode);
|
values.put("version_code",report.versionCode);
|
||||||
values.put("app_id",appId);
|
values.put("app_id",appId);
|
||||||
|
values.put("source",report.source);
|
||||||
|
|
||||||
if(!existReport(db,report.id)) {
|
if(!existReport(db,report.id)) {
|
||||||
values.put("id",report.id);
|
values.put("id",report.id);
|
||||||
|
@ -180,36 +213,91 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
db.insert("trackers_reports",null,values);
|
db.insert("trackers_reports",null,values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Report getReportFor(String packageName, String version) {
|
public Report getReportFor(String packageName, String version, String source) {
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
String[] columns = {"id"};
|
String[] columns = {"id"};
|
||||||
String where = "package = ?";
|
String where = "package = ?";
|
||||||
String[] whereArgs = {packageName};
|
String[] whereArgs = {packageName};
|
||||||
Cursor cursor = getReadableDatabase().query("applications",columns,where,whereArgs,null,null,null);
|
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||||
if(cursor.moveToFirst()) {
|
if(cursor.moveToFirst()) {
|
||||||
long appId = cursor.getLong(0);
|
long appId = cursor.getLong(0);
|
||||||
cursor.close();
|
cursor.close();
|
||||||
where = "app_id = ? and version = ?";
|
where = "app_id = ? and version = ? and source = ?";
|
||||||
whereArgs = new String[2];
|
whereArgs = new String[3];
|
||||||
whereArgs[0] = String.valueOf(appId);
|
whereArgs[0] = String.valueOf(appId);
|
||||||
whereArgs[1] = version;
|
whereArgs[1] = version;
|
||||||
|
whereArgs[2] = source;
|
||||||
String order = "id ASC";
|
String order = "id ASC";
|
||||||
cursor = getReadableDatabase().query("reports",columns,where,whereArgs,null,null,order);
|
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||||
long reportId;
|
long reportId;
|
||||||
if(cursor.moveToFirst()) {
|
if(cursor.moveToFirst()) {
|
||||||
reportId = cursor.getLong(0);
|
reportId = cursor.getLong(0);
|
||||||
|
cursor.close();
|
||||||
} else {
|
} else {
|
||||||
|
cursor.close();
|
||||||
columns = new String[2];
|
columns = new String[2];
|
||||||
columns[0] = "id";
|
columns[0] = "id";
|
||||||
columns[1] = "creation";
|
columns[1] = "creation";
|
||||||
where = "app_id = ?";
|
where = "app_id = ? and source = ?";
|
||||||
whereArgs = new String[1];
|
whereArgs = new String[2];
|
||||||
whereArgs[0] = String.valueOf(appId);
|
whereArgs[0] = String.valueOf(appId);
|
||||||
|
whereArgs[1] = source;
|
||||||
order = "creation DESC";
|
order = "creation DESC";
|
||||||
//search a recent reports
|
//search a recent reports
|
||||||
cursor = getReadableDatabase().query("reports",columns,where,whereArgs,null,null,order);
|
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||||
if(cursor.moveToFirst()) {
|
if(cursor.moveToFirst()) {
|
||||||
reportId = cursor.getLong(0);
|
reportId = cursor.getLong(0);
|
||||||
|
cursor.close();
|
||||||
} else {
|
} else {
|
||||||
|
cursor.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getReport(reportId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cursor.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Report getReportFor(String packageName, long version, String source) {
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
|
String[] columns = {"id"};
|
||||||
|
String where = "package = ?";
|
||||||
|
String[] whereArgs = {packageName};
|
||||||
|
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||||
|
if(cursor.moveToFirst()) {
|
||||||
|
long appId = cursor.getLong(0);
|
||||||
|
cursor.close();
|
||||||
|
where = "app_id = ? and version_code = ? and source = ?";
|
||||||
|
whereArgs = new String[3];
|
||||||
|
whereArgs[0] = String.valueOf(appId);
|
||||||
|
whereArgs[1] = String.valueOf(version);
|
||||||
|
whereArgs[2] = source;
|
||||||
|
String order = "id ASC";
|
||||||
|
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||||
|
long reportId;
|
||||||
|
if(cursor.moveToFirst()) {
|
||||||
|
reportId = cursor.getLong(0);
|
||||||
|
cursor.close();
|
||||||
|
} else {
|
||||||
|
cursor.close();
|
||||||
|
columns = new String[2];
|
||||||
|
columns[0] = "id";
|
||||||
|
columns[1] = "creation";
|
||||||
|
where = "app_id = ? and source = ?";
|
||||||
|
whereArgs = new String[2];
|
||||||
|
whereArgs[0] = String.valueOf(appId);
|
||||||
|
whereArgs[1] = source;
|
||||||
|
order = "creation DESC";
|
||||||
|
//search a recent reports
|
||||||
|
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||||
|
if(cursor.moveToFirst()) {
|
||||||
|
reportId = cursor.getLong(0);
|
||||||
|
cursor.close();
|
||||||
|
} else {
|
||||||
|
cursor.close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,12 +310,15 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Report getReport(long reportId) {
|
private Report getReport(long reportId) {
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
String where = "id = ?";
|
String where = "id = ?";
|
||||||
String[] whereArgs = {String.valueOf(reportId)};
|
String[] whereArgs = {String.valueOf(reportId)};
|
||||||
Cursor cursor = getReadableDatabase().query("reports",null,where,whereArgs,null,null,null);
|
Cursor cursor = db.query("reports",null,where,whereArgs,null,null,null);
|
||||||
//get report
|
//get report
|
||||||
if(!cursor.moveToFirst())
|
if(!cursor.moveToFirst()) {
|
||||||
|
cursor.close();
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Report report = new Report();
|
Report report = new Report();
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
@ -235,19 +326,23 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
long creation = cursor.getLong(col++);
|
long creation = cursor.getLong(col++);
|
||||||
report.creationDate = Calendar.getInstance();
|
report.creationDate = Calendar.getInstance();
|
||||||
report.creationDate.setTimeInMillis(creation);
|
report.creationDate.setTimeInMillis(creation);
|
||||||
|
report.creationDate.set(Calendar.MILLISECOND,0);
|
||||||
long update = cursor.getLong(col++);
|
long update = cursor.getLong(col++);
|
||||||
report.updateDate = Calendar.getInstance();
|
report.updateDate = Calendar.getInstance();
|
||||||
report.updateDate.setTimeInMillis(update);
|
report.updateDate.setTimeInMillis(update);
|
||||||
|
report.updateDate.set(Calendar.MILLISECOND,0);
|
||||||
report.downloads = cursor.getString(col++);
|
report.downloads = cursor.getString(col++);
|
||||||
report.version = cursor.getString(col++);
|
report.version = cursor.getString(col++);
|
||||||
report.versionCode = cursor.getLong(col++);
|
report.versionCode = cursor.getLong(col++);
|
||||||
report.appId = cursor.getLong(col);
|
report.appId = cursor.getLong(col++);
|
||||||
|
report.source = cursor.getString(col);
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
report.trackers = new HashSet<>();
|
report.trackers = new HashSet<>();
|
||||||
where = "report_id = ?";
|
where = "report_id = ?";
|
||||||
String[] columns = {"tracker_id"};
|
String[] columns = {"tracker_id"};
|
||||||
String order = "tracker_id DESC";
|
String order = "tracker_id DESC";
|
||||||
cursor = getReadableDatabase().query("trackers_reports",columns,where,whereArgs,null,null,order);
|
cursor = db.query("trackers_reports",columns,where,whereArgs,null,null,order);
|
||||||
//get trackersIds
|
//get trackersIds
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
report.trackers.add(cursor.getLong(0));
|
report.trackers.add(cursor.getLong(0));
|
||||||
|
@ -270,10 +365,11 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
return creator;
|
return creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tracker getTracker(long trackerId) {
|
public Tracker getTracker(long trackerId) {
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
String where = "id = ?";
|
String where = "id = ?";
|
||||||
String[] whereArgs = {String.valueOf(trackerId)};
|
String[] whereArgs = {String.valueOf(trackerId)};
|
||||||
Cursor cursor = getReadableDatabase().query("trackers",null,where,whereArgs,null,null,null,null);
|
Cursor cursor = db.query("trackers",null,where,whereArgs,null,null,null,null);
|
||||||
Tracker tracker = null;
|
Tracker tracker = null;
|
||||||
if(cursor.moveToFirst())
|
if(cursor.moveToFirst())
|
||||||
{
|
{
|
||||||
|
@ -309,4 +405,40 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
||||||
insertOrUpdateTracker(db,tracker);
|
insertOrUpdateTracker(db,tracker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String,String> getSources(String packageName) {
|
||||||
|
String where = "package = ?";
|
||||||
|
String[] whereArgs = {packageName};
|
||||||
|
String[] columns = {"sources"};
|
||||||
|
Cursor cursor = getReadableDatabase().query("applications",columns,where,whereArgs,null,null,null,null);
|
||||||
|
String sourcesStr="";
|
||||||
|
if(cursor.moveToFirst())
|
||||||
|
{
|
||||||
|
sourcesStr = cursor.getString(0);
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return extractSources(sourcesStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSourcesStr(Map<String,String> sources) {
|
||||||
|
StringBuilder sourceStr = new StringBuilder();
|
||||||
|
for(Map.Entry<String,String> entry : sources.entrySet()) {
|
||||||
|
sourceStr.append(entry.getKey()).append(":").append(entry.getValue()).append("|");
|
||||||
|
}
|
||||||
|
return sourceStr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> extractSources(String sourcesStr) {
|
||||||
|
Map<String,String> sources = new HashMap<>();
|
||||||
|
String[] sourceList = sourcesStr.split("\\|");
|
||||||
|
for(String sourceItem : sourceList){
|
||||||
|
if(!sourceItem.isEmpty()) {
|
||||||
|
String[] data = sourceItem.split(":");
|
||||||
|
if(data.length == 2)
|
||||||
|
sources.put(data[0], data[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,6 @@ import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
|
||||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -42,14 +36,27 @@ import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Singleton that handle all network connection
|
Singleton that handle all network connection
|
||||||
*/
|
*/
|
||||||
|
@ -195,8 +202,14 @@ public class NetworkManager {
|
||||||
JSONObject tracker = trackers.getJSONObject(trackerId);
|
JSONObject tracker = trackers.getJSONObject(trackerId);
|
||||||
Tracker track = parseTracker(tracker,trackerId);
|
Tracker track = parseTracker(tracker,trackerId);
|
||||||
trackersList.add(track);
|
trackersList.add(track);
|
||||||
|
if (trackersList.size() == 20) {
|
||||||
|
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
||||||
|
trackersList.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
if(!trackersList.isEmpty())
|
||||||
|
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
||||||
|
trackersList.clear();
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
mes.listener.onError(mes.context.getString(R.string.json_error));
|
mes.listener.onError(mes.context.getString(R.string.json_error));
|
||||||
}
|
}
|
||||||
|
@ -207,7 +220,7 @@ public class NetworkManager {
|
||||||
mes.listener.onProgress(R.string.get_reports_connection,0,0);
|
mes.listener.onProgress(R.string.get_reports_connection,0,0);
|
||||||
URL url;
|
URL url;
|
||||||
try {
|
try {
|
||||||
url = new URL(apiUrl+"applications");
|
url = new URL(apiUrl+"applications?option=short");
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
return;
|
||||||
|
@ -218,45 +231,64 @@ public class NetworkManager {
|
||||||
|
|
||||||
|
|
||||||
if(object != null) {
|
if(object != null) {
|
||||||
List<String> handles = new ArrayList<>();
|
Map<String,Map<String,String>> handles = new HashMap<>();
|
||||||
|
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
||||||
|
if (packages == null)
|
||||||
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JSONArray applications = object.getJSONArray("applications");
|
JSONArray applications = object.getJSONArray("applications");
|
||||||
|
|
||||||
|
//manage handles map (handle,UAID)
|
||||||
for(int i = 0; i<applications.length(); i++) {
|
for(int i = 0; i<applications.length(); i++) {
|
||||||
JSONObject app = applications.getJSONObject(i);
|
JSONObject app = applications.getJSONObject(i);
|
||||||
String handle = app.getString("handle");
|
String handle = app.getString("handle");
|
||||||
handles.add(handle);
|
String auid = app.getString("app_uid");
|
||||||
|
String source = app.getString("source");
|
||||||
|
Map<String,String> sources = handles.get(handle);
|
||||||
|
if(sources == null)
|
||||||
|
sources = new HashMap<>();
|
||||||
|
|
||||||
|
sources.put(source,auid);
|
||||||
|
if (packages.contains(handle))
|
||||||
|
handles.put(handle,sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//remove app not analyzed by Exodus
|
||||||
|
packages.retainAll(handles.keySet());
|
||||||
|
|
||||||
|
// Add some random packages to avoid tracking
|
||||||
|
Random rand = new Random(Thread.currentThread().getId());
|
||||||
|
int alea = rand.nextInt(120) % 10 + 11;
|
||||||
|
for(int i = 0 ; i < alea; i++) {
|
||||||
|
int val = rand.nextInt(applications.length());
|
||||||
|
JSONObject app = applications.getJSONObject(val);
|
||||||
|
String handle = app.getString("handle");
|
||||||
|
handles.put(handle,new HashMap<>());
|
||||||
|
packages.add(handle);
|
||||||
|
}
|
||||||
|
//shuffle the list
|
||||||
|
Collections.shuffle(packages);
|
||||||
|
object.remove("applications");
|
||||||
|
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
mes.listener.onError(mes.context.getString(R.string.json_error));
|
mes.listener.onError(mes.context.getString(R.string.json_error));
|
||||||
}
|
}
|
||||||
getReports(mes,handles);
|
object = null;
|
||||||
|
getReports(mes,handles,packages);
|
||||||
}
|
}
|
||||||
mes.listener.onSuccess();
|
mes.listener.onSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getReports(Message mes, List<String> handles) {
|
private void getReports(Message mes, Map<String, Map<String,String>> handles, ArrayList<String> packages) {
|
||||||
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
|
||||||
if(packages == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
packages.retainAll(handles);
|
|
||||||
|
|
||||||
// Add some random packages to avoid tracking
|
|
||||||
Random rand = new Random(Thread.currentThread().getId());
|
|
||||||
int alea = rand.nextInt(120) % 10 + 11;
|
|
||||||
for(int i = 0 ; i < alea; i++) {
|
|
||||||
int val = rand.nextInt(handles.size());
|
|
||||||
packages.add(handles.get(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < packages.size(); i++) {
|
for(int i = 0; i < packages.size(); i++) {
|
||||||
mes.listener.onProgress(R.string.parse_application,i+1,packages.size());
|
mes.listener.onProgress(R.string.parse_application,i+1,packages.size());
|
||||||
getReport(mes,packages.get(i));
|
getReport(mes,packages.get(i),handles.get(packages.get(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getReport(Message mes, String handle) {
|
private void getReport(Message mes, String handle, Map<String,String> sources) {
|
||||||
URL url;
|
URL url;
|
||||||
try {
|
try {
|
||||||
url = new URL(apiUrl+"search/"+handle);
|
url = new URL(apiUrl+"search/"+handle);
|
||||||
|
@ -272,6 +304,7 @@ public class NetworkManager {
|
||||||
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
||||||
if(packages != null && packages.contains(handle)) {
|
if(packages != null && packages.contains(handle)) {
|
||||||
Application app = parseApplication(application, handle);
|
Application app = parseApplication(application, handle);
|
||||||
|
app.sources = sources;
|
||||||
DatabaseManager.getInstance(mes.context).insertOrUpdateApplication(app);
|
DatabaseManager.getInstance(mes.context).insertOrUpdateApplication(app);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
|
@ -285,6 +318,7 @@ public class NetworkManager {
|
||||||
application.packageName = packageName;
|
application.packageName = packageName;
|
||||||
application.creator = object.getString("creator");
|
application.creator = object.getString("creator");
|
||||||
application.name = object.getString("name");
|
application.name = object.getString("name");
|
||||||
|
|
||||||
//parse Report
|
//parse Report
|
||||||
application.reports = new HashSet<>();
|
application.reports = new HashSet<>();
|
||||||
JSONArray reports = object.getJSONArray("reports");
|
JSONArray reports = object.getJSONArray("reports");
|
||||||
|
@ -300,6 +334,7 @@ public class NetworkManager {
|
||||||
report.id = object.getLong("id");
|
report.id = object.getLong("id");
|
||||||
report.downloads = object.getString("downloads");
|
report.downloads = object.getString("downloads");
|
||||||
report.version = object.getString("version");
|
report.version = object.getString("version");
|
||||||
|
report.source = object.getString("source");
|
||||||
if(!object.getString("version_code").isEmpty())
|
if(!object.getString("version_code").isEmpty())
|
||||||
report.versionCode = Long.parseLong(object.getString("version_code"));
|
report.versionCode = Long.parseLong(object.getString("version_code"));
|
||||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
|
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
|
||||||
|
@ -307,10 +342,12 @@ public class NetworkManager {
|
||||||
report.updateDate = Calendar.getInstance();
|
report.updateDate = Calendar.getInstance();
|
||||||
report.updateDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
report.updateDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
report.updateDate.setTime(dateFormat.parse(object.getString("updated_at")));
|
report.updateDate.setTime(dateFormat.parse(object.getString("updated_at")));
|
||||||
|
report.updateDate.set(Calendar.MILLISECOND,0);
|
||||||
|
|
||||||
report.creationDate = Calendar.getInstance();
|
report.creationDate = Calendar.getInstance();
|
||||||
report.creationDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
report.creationDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
report.creationDate.setTime(dateFormat.parse(object.getString("creation_date")));
|
report.creationDate.setTime(dateFormat.parse(object.getString("creation_date")));
|
||||||
|
report.creationDate.set(Calendar.MILLISECOND,0);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
package org.eu.exodus_privacy.exodusprivacy.objects;
|
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class Application {
|
public class Application {
|
||||||
|
@ -26,6 +28,7 @@ public class Application {
|
||||||
public String name;
|
public String name;
|
||||||
public String creator;
|
public String creator;
|
||||||
public Set<Report> reports;
|
public Set<Report> reports;
|
||||||
|
public Map<String,String> sources;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
@ -35,13 +38,13 @@ public class Application {
|
||||||
Application that = (Application) o;
|
Application that = (Application) o;
|
||||||
|
|
||||||
if (id != that.id) return false;
|
if (id != that.id) return false;
|
||||||
return packageName.equals(that.packageName);
|
return packageName != null ? packageName.equals(that.packageName) : that.packageName == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = (int) (id ^ (id >>> 32));
|
int result = (int) (id ^ (id >>> 32));
|
||||||
result = 31 * result + packageName.hashCode();
|
result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package org.eu.exodus_privacy.exodusprivacy.objects;
|
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
public class Permission {
|
public class Permission {
|
||||||
public String name;
|
public String name;
|
||||||
public String fullName;
|
public String fullName;
|
||||||
public String description;
|
public String description;
|
||||||
|
public Drawable icon;
|
||||||
|
public boolean dangerous;
|
||||||
public boolean expanded = false;
|
public boolean expanded = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ public class Report {
|
||||||
public long versionCode;
|
public long versionCode;
|
||||||
public Set<Long> trackers;
|
public Set<Long> trackers;
|
||||||
public long appId;
|
public long appId;
|
||||||
|
public String source;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PermissionGroupInfo;
|
||||||
|
import android.content.pm.PermissionInfo;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||||
|
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ReportDisplay {
|
||||||
|
public Report report;
|
||||||
|
public String packageName;
|
||||||
|
public String versionName;
|
||||||
|
public String displayName;
|
||||||
|
public String creator;
|
||||||
|
public long versionCode;
|
||||||
|
public Drawable logo;
|
||||||
|
public List<Permission> permissions;
|
||||||
|
public Set<Tracker> trackers;
|
||||||
|
public String source;
|
||||||
|
public String viewOnStore;
|
||||||
|
|
||||||
|
|
||||||
|
private ReportDisplay(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReportDisplay buildReportDisplay(Context context, ApplicationViewModel model, PackageManager manager, PackageInfo info) {
|
||||||
|
ReportDisplay reportDisplay = new ReportDisplay();
|
||||||
|
reportDisplay.packageName = model.packageName;
|
||||||
|
reportDisplay.versionName = model.versionName;
|
||||||
|
reportDisplay.versionCode = model.versionCode;
|
||||||
|
reportDisplay.displayName = model.label.toString();
|
||||||
|
|
||||||
|
reportDisplay.report = model.report;
|
||||||
|
reportDisplay.source = context.getString(R.string.source,model.source);
|
||||||
|
reportDisplay.viewOnStore = context.getString(model.source.equals("google")? R.string.view_on_google_play : R.string.view_on_fdroid);
|
||||||
|
|
||||||
|
reportDisplay.trackers = model.trackers;
|
||||||
|
|
||||||
|
if (reportDisplay.report != null)
|
||||||
|
reportDisplay.creator = DatabaseManager.getInstance(context).getCreator(reportDisplay.report.appId);
|
||||||
|
|
||||||
|
List<Permission> requestedPermissions= new ArrayList<>();
|
||||||
|
if (info.requestedPermissions != null) {
|
||||||
|
for(int i = 0; i < info.requestedPermissions.length; i++) {
|
||||||
|
Permission permission = new Permission();
|
||||||
|
permission.fullName = info.requestedPermissions[i];
|
||||||
|
try {
|
||||||
|
PermissionInfo permissionInfo = manager.getPermissionInfo(permission.fullName,PackageManager.GET_META_DATA);
|
||||||
|
if(permissionInfo.loadDescription(manager) != null)
|
||||||
|
permission.description = permissionInfo.loadDescription(manager).toString();
|
||||||
|
if(permissionInfo.loadLabel(manager) != null)
|
||||||
|
permission.name = permissionInfo.loadLabel(manager).toString();
|
||||||
|
permission.dangerous = permissionInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS;
|
||||||
|
if(permission.fullName.equals(Manifest.permission.WRITE_SETTINGS) || permission.fullName.equals(Manifest.permission.SYSTEM_ALERT_WINDOW)) //Special permissions
|
||||||
|
permission.dangerous = true;
|
||||||
|
|
||||||
|
if (permissionInfo.group != null) {
|
||||||
|
PermissionGroupInfo permissionGroupInfo = manager.getPermissionGroupInfo(permissionInfo.group, PackageManager.GET_META_DATA);
|
||||||
|
if(permissionGroupInfo.loadIcon(manager) != null)
|
||||||
|
permission.icon = permissionGroupInfo.loadIcon(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.getLocalizedMessage();
|
||||||
|
}
|
||||||
|
requestedPermissions.add(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reportDisplay.permissions = requestedPermissions;
|
||||||
|
|
||||||
|
reportDisplay.logo = model.icon;
|
||||||
|
|
||||||
|
return reportDisplay;
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 384 B |
Before Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 492 B |
Before Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 967 B |
|
@ -0,0 +1,6 @@
|
||||||
|
<vector android:height="24dp" android:viewportHeight="16"
|
||||||
|
android:viewportWidth="4" android:width="6dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#E61718" android:fillType="evenOdd"
|
||||||
|
android:pathData="M0.18,1.5C0.18,0.6716 0.8516,0 1.68,0C2.5084,0 3.18,0.6716 3.18,1.5L3.18,8.39C3.18,9.2184 2.5084,9.89 1.68,9.89C0.8516,9.89 0.18,9.2184 0.18,8.39L0.18,1.5ZM1.72,15.01C0.7701,15.01 0,14.2399 0,13.29C0,12.3401 0.7701,11.57 1.72,11.57C2.6699,11.57 3.44,12.3401 3.44,13.29C3.44,14.2399 2.6699,15.01 1.72,15.01Z"
|
||||||
|
android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector android:height="100dp" android:viewportHeight="54"
|
||||||
|
android:viewportWidth="54" android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillAlpha="1" android:fillColor="#684971"
|
||||||
|
android:pathData="M2.1737,27a24.8263,24.5976 0,1 0,49.6526 0a24.8263,24.5976 0,1 0,-49.6526 0z"
|
||||||
|
android:strokeColor="#00000000" android:strokeWidth="0.0297731"/>
|
||||||
|
<path android:fillAlpha="1" android:fillColor="#ffffff"
|
||||||
|
android:pathData="m22.6353,26.1025c-4.3263,-1.5231 -6.4894,-3.8295 -6.4894,-6.9192 -0,-2.4369 1.1474,-4.3843 3.4423,-5.8421 2.2949,-1.4578 5.1443,-2.1867 8.5482,-2.1867 3.0964,0 5.556,0.5059 7.3788,1.5176 1.8227,1.0118 2.7341,2.2248 2.7341,3.6391 -0,0.7398 -0.2855,1.3871 -0.8565,1.9419 -0.571,0.5549 -1.2298,0.8323 -1.9765,0.8323 -1.2298,0 -2.24,-0.8486 -3.0306,-2.5457 -1.098,-2.3499 -2.7451,-3.5248 -4.9412,-3.5249 -1.7349,0 -3.1624,0.5657 -4.2823,1.6972 -1.12,1.1315 -1.68,2.7089 -1.68,4.7325 -0,3.9818 2.0753,5.9727 6.2259,5.9727 0.4392,0 0.9443,-0.0435 1.5153,-0.1305 0.9882,-0.1305 1.7568,-0.1958 2.3059,-0.1958 1.3396,0 2.0094,0.3808 2.0094,1.1423 -0,0.8486 -0.6808,1.2729 -2.0424,1.2729 -0.4832,0 -1.2079,-0.0761 -2.1741,-0.2285 -0.7247,-0.1305 -1.2847,-0.1958 -1.68,-0.1958 -4.3922,0 -6.5882,2.2194 -6.5882,6.6581 -0,2.1541 0.5819,3.8893 1.7459,5.2057 1.1639,1.3164 2.789,1.9746 4.8753,1.9746 2.6133,0 4.3482,-1.3381 5.2047,-4.0144 0.4392,-1.4143 0.9278,-2.3934 1.4659,-2.9374 0.538,-0.544 1.2572,-0.8159 2.1576,-0.8159 0.7466,0 1.4219,0.2665 2.0259,0.7996 0.6039,0.5331 0.9059,1.213 0.9059,2.0399 -0,1.98 -1.12,3.6173 -3.36,4.912 -2.24,1.2946 -4.9522,1.9419 -8.1365,1.9419 -3.4918,0 -6.5937,-0.8268 -9.3059,-2.4805 -2.7122,-1.6536 -4.0682,-3.8621 -4.0682,-6.6254 -0,-3.4596 2.6902,-6.0053 8.0706,-7.6372z"
|
||||||
|
android:strokeAlpha="1" android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="butt" android:strokeLineJoin="miter" android:strokeWidth="0.03275258"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<vector android:height="24dp" android:viewportHeight="20"
|
||||||
|
android:viewportWidth="20" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FFFFFFFF" android:pathData="M15.95,10.78c0.03,-0.25 0.05,-0.51 0.05,-0.78s-0.02,-0.53 -0.06,-0.78l1.69,-1.32c0.15,-0.12 0.19,-0.34 0.1,-0.51l-1.6,-2.77c-0.1,-0.18 -0.31,-0.24 -0.49,-0.18l-1.99,0.8c-0.42,-0.32 -0.86,-0.58 -1.35,-0.78L12,2.34c-0.03,-0.2 -0.2,-0.34 -0.4,-0.34H8.4c-0.2,0 -0.36,0.14 -0.39,0.34l-0.3,2.12c-0.49,0.2 -0.94,0.47 -1.35,0.78l-1.99,-0.8c-0.18,-0.07 -0.39,0 -0.49,0.18l-1.6,2.77c-0.1,0.18 -0.06,0.39 0.1,0.51l1.69,1.32c-0.04,0.25 -0.07,0.52 -0.07,0.78s0.02,0.53 0.06,0.78L2.37,12.1c-0.15,0.12 -0.19,0.34 -0.1,0.51l1.6,2.77c0.1,0.18 0.31,0.24 0.49,0.18l1.99,-0.8c0.42,0.32 0.86,0.58 1.35,0.78l0.3,2.12c0.04,0.2 0.2,0.34 0.4,0.34h3.2c0.2,0 0.37,-0.14 0.39,-0.34l0.3,-2.12c0.49,-0.2 0.94,-0.47 1.35,-0.78l1.99,0.8c0.18,0.07 0.39,0 0.49,-0.18l1.6,-2.77c0.1,-0.18 0.06,-0.39 -0.1,-0.51l-1.67,-1.32zM10,13c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3 3,1.35 3,3 -1.35,3 -3,3z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorDarkOrange"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorGreen"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorLightBlue"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorLightRed"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorLightYellow"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorPrimary"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorRed"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorYellow"/>
|
||||||
|
<corners android:radius="5dp"/>
|
||||||
|
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||||
|
</shape>
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/base_info"
|
android:id="@+id/base_info"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -29,15 +31,44 @@
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/app_tracker_nb"
|
android:orientation="horizontal"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_permission_nb"
|
android:textAlignment="center"
|
||||||
|
android:background="@drawable/square_green"
|
||||||
|
android:id="@+id/app_tracker_nb"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
<TextView
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/trackers"
|
||||||
|
android:id="@+id/app_tracker"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:background="@drawable/square_green"
|
||||||
|
android:id="@+id/app_permission_nb"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
<TextView
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:text="@string/permissions"
|
||||||
|
android:id="@+id/app_permission"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
|
@ -52,6 +83,12 @@
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_below="@+id/base_info"
|
android:layout_below="@+id/base_info"
|
||||||
|
android:id="@+id/source"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:layout_below="@+id/source"
|
||||||
android:id="@+id/other_version"
|
android:id="@+id/other_version"
|
||||||
android:text="@string/tested"
|
android:text="@string/tested"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -1,76 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout
|
<layout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context="org.eu.exodus_privacy.exodusprivacy.MainActivity"
|
tools:context="org.eu.exodus_privacy.exodusprivacy.MainActivity"
|
||||||
>
|
>
|
||||||
<data/>
|
<data/>
|
||||||
<android.support.constraint.ConstraintLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/app_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
android:scrollbars="vertical"/>
|
||||||
<LinearLayout
|
|
||||||
android:visibility="gone"
|
|
||||||
android:id="@+id/layout_progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:id="@+id/status_progress"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress"
|
|
||||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
|
||||||
android:progressDrawable="@drawable/progressbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="5dp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_package_manager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="@string/no_package_manager"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_app_found"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="@string/no_app_found"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/swipe_refresh"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/layout_progress"
|
|
||||||
>
|
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
|
||||||
android:id="@+id/app_list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
</layout>
|
</layout>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:context="org.eu.exodus_privacy.exodusprivacy.MainActivity"
|
||||||
|
>
|
||||||
|
<data/>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
>
|
||||||
|
<LinearLayout
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/layout_progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:id="@+id/status_progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:progressDrawable="@drawable/progressbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_package_manager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_package_manager"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_app_found"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_app_found"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/logo"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
android:src="@drawable/ic_logo_purple"
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="200dp" />
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/retrieve_app"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/logo" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/swipe_refresh"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/layout_progress"
|
||||||
|
>
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/app_list_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</layout>
|
|
@ -8,12 +8,8 @@
|
||||||
>
|
>
|
||||||
<data/>
|
<data/>
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:layout_marginLeft="10dp"
|
|
||||||
android:layout_marginStart="10dp"
|
android:layout_marginStart="10dp"
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:layout_marginBottom="5dp"
|
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
|
@ -1,19 +1,56 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
>
|
|
||||||
<data/>
|
<data/>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/main_layout"
|
android:id="@+id/main_layout"
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
<LinearLayout
|
android:layout_marginTop="10dp"
|
||||||
android:gravity="center"
|
android:layout_marginBottom="10dp"
|
||||||
android:orientation="horizontal"
|
>
|
||||||
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
/>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dangerous"
|
||||||
|
android:src="@drawable/ic_danger"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permission_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_toEndOf="@id/dangerous"
|
||||||
|
android:layout_toStartOf="@id/arrow"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permission_short"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_toEndOf="@id/dangerous"
|
||||||
|
android:layout_toStartOf="@id/arrow"
|
||||||
|
android:layout_below="@id/permission_name"
|
||||||
|
android:textStyle="italic"
|
||||||
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:text="▼"
|
android:text="▼"
|
||||||
android:id="@+id/arrow"
|
android:id="@+id/arrow"
|
||||||
|
@ -21,20 +58,18 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:layout_marginLeft="5dp"
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
/>
|
/>
|
||||||
<TextView
|
</RelativeLayout>
|
||||||
android:id="@+id/permission_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</LinearLayout>
|
|
||||||
<TextView
|
<TextView
|
||||||
android:paddingLeft="20dp"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:id="@+id/permission_description"
|
android:id="@+id/permission_description"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="66dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textStyle="italic"
|
||||||
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -1,130 +1,444 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout
|
<layout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
>
|
>
|
||||||
<data/>
|
<data>
|
||||||
<ScrollView
|
<import type="androidx.core.content.ContextCompat"/>
|
||||||
|
<import type="android.view.View"/>
|
||||||
|
<variable
|
||||||
|
name="reportInfo"
|
||||||
|
type="org.eu.exodus_privacy.exodusprivacy.ReportViewModel" />
|
||||||
|
</data>
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_height="wrap_content">
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:id="@+id/base_info"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent">
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/logo"
|
android:id="@+id/logo"
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
/>
|
android:layout_marginTop="20dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@{reportInfo.logo}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:layout_marginLeft="2dp"
|
android:id="@+id/name"
|
||||||
android:layout_marginStart="2dp"
|
android:layout_width="match_parent"
|
||||||
android:orientation="vertical"
|
android:layout_height="0dp"
|
||||||
|
android:text="@{reportInfo.name}"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/logo"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:textSize="30sp"
|
||||||
|
android:textColor="@color/colorPurple"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/dummy"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/trackers_nb"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:text="@{reportInfo.trackerNumberStr}"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/dummy"
|
||||||
|
android:background="@{ContextCompat.getDrawable(context,reportInfo.trackerColor)}"
|
||||||
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:textColor="@color/textColorWhite"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="22sp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/trackers_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/trackers"
|
||||||
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/trackers_nb"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/trackers_nb"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permissions_nb"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:text="@{reportInfo.permissionNumberStr}"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/trackers_nb"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:background="@{ContextCompat.getDrawable(context,reportInfo.permissionColor)}"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:textColor="@color/textColorWhite"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="22sp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permissions_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/permissions"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/trackers_nb"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/permissions_nb"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/installed_version"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/installed"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/permissions_nb"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDark"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/installed_version_value"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{reportInfo.installedVersion}"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/installed_version"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/permissions_nb"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/report_version"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/report_version"
|
||||||
|
android:visibility="@{reportInfo.reportVersionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/installed_version_value"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/report_version_value"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{reportInfo.reportVersion}"
|
||||||
|
android:visibility="@{reportInfo.reportVersionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/report_version"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/installed_version_value"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/source"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{reportInfo.source}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/report_version_value"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/creator"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/created_by"
|
||||||
|
android:visibility="@{reportInfo.creatorVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/source"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/creator_value"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.creatorVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/creator"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/source"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/report_date"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.reportVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/creator_value"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/textColorDarkLight"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/report_url"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
>
|
android:autoLink="web"
|
||||||
<TextView
|
android:text="@string/view_on_exodus"
|
||||||
android:id="@+id/name"
|
android:visibility="@{reportInfo.reportVisibility ? View.VISIBLE : View.GONE}"
|
||||||
android:text="test"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
android:textAlignment="textEnd"
|
||||||
android:layout_width="match_parent"
|
app:layout_constraintTop_toBottomOf="@id/report_date"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_marginTop="5dp"
|
||||||
<TextView
|
android:layout_marginStart="20dp"
|
||||||
android:text="Creator"
|
android:layout_marginEnd="20dp"
|
||||||
android:id="@+id/creator"
|
android:textSize="16sp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
android:textColor="@color/colorPurple"/>
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<TextView
|
|
||||||
android:text="installed version"
|
|
||||||
android:id="@+id/installed_version"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<TextView
|
|
||||||
android:text="Report version"
|
|
||||||
android:id="@+id/report_version"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/report_url"
|
|
||||||
android:autoLink="web"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/analysed"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/analysed"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
|
||||||
/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_below="@id/base_info"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
>
|
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:id="@+id/tracker_layout"
|
android:id="@+id/view_store"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="50"
|
android:autoLink="web"
|
||||||
android:orientation="vertical">
|
android:text="@{reportInfo.viewOnStore}"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/report_url"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/colorPurple"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/trackers_title"
|
android:id="@+id/trackers_nb_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="40dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:background="@color/colorPrimary"
|
android:text="@{reportInfo.trackerNumberStr}"
|
||||||
android:text="@string/trackers"
|
android:layout_marginStart="20dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
android:layout_marginTop="30dp"
|
||||||
android:textColor="@android:color/white" />
|
app:layout_constraintTop_toBottomOf="@id/analysed"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:background="@{ContextCompat.getDrawable(context,reportInfo.trackerColor)}"
|
||||||
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorWhite"
|
||||||
|
/>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<TextView
|
||||||
android:id="@+id/trackers"
|
android:id="@+id/trackers_title_list"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_width="0dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:text="@string/trackers"
|
||||||
android:layout_height="wrap_content" />
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
</LinearLayout>
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/analysed"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/trackers_nb_list"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:orientation="vertical"
|
android:id="@+id/code_signature"
|
||||||
android:layout_weight="50"
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/trackers_nb_list"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/trackers"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
<TextView
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
android:background="@color/colorPrimary"
|
android:layout_marginTop="5dp"
|
||||||
android:id="@+id/permissions_title"
|
android:layout_marginBottom="5dp"
|
||||||
android:text="@string/permissions"
|
android:layout_marginStart="20dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
android:layout_marginEnd="20dp"
|
||||||
android:layout_width="match_parent"
|
app:layout_constraintTop_toBottomOf="@id/code_signature"
|
||||||
android:layout_height="wrap_content"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:textColor="@android:color/white"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<TextView
|
||||||
android:id="@+id/permissions"
|
android:id="@+id/tracker_explanation"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_width="0dp"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||||
android:layout_height="wrap_content"
|
android:text="@string/tracker_infos"
|
||||||
/>
|
android:layout_marginTop="5dp"
|
||||||
</LinearLayout>
|
android:layout_marginBottom="5dp"
|
||||||
</LinearLayout>
|
android:layout_marginStart="20dp"
|
||||||
</RelativeLayout>
|
android:layout_marginEnd="20dp"
|
||||||
</ScrollView>
|
app:layout_constraintTop_toBottomOf="@id/trackers"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permissions_nb_list"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:text="@{reportInfo.permissionNumberStr}"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_explanation"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:background="@{ContextCompat.getDrawable(context,reportInfo.permissionColor)}"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorWhite"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permissions_title_list"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/permissions"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_explanation"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/permissions_nb_list"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/code_permission"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/permissions_nb_list"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/permissions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/permission_explanation_dangerous"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/code_permission" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permission_explanation_dangerous"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.hasPermissionDangerous ? View.VISIBLE : View.GONE}"
|
||||||
|
android:text="@string/permission_infos_dangerous"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/permission_explanation"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/permission_explanation"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="@{reportInfo.permissionVisibility ? View.VISIBLE : View.GONE}"
|
||||||
|
android:text="@string/permission_infos"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/analysed"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/analysed"
|
||||||
|
android:visibility="@{reportInfo.trackerVisibility ? View.GONE : View.VISIBLE}"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/view_store"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
</layout>
|
</layout>
|
|
@ -0,0 +1,213 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
>
|
||||||
|
<data>
|
||||||
|
</data>
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textSize="30sp"
|
||||||
|
android:textColor="@color/colorPurple"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"/>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tracker_presence"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/name"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tracker_presence_nb"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/tracker_presence"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/tracker_presence"
|
||||||
|
android:textColor="@color/textColorDark"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="14sp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dummy"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/tracker_presence"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/tracker_presence_nb"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tracker_url"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:text="@string/tracker_web_page"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_presence"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@color/colorPurple"/>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_url"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detection_rules"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/detection_rules"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/description"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/code_detection_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/code_signature"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/detection_rules"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/code_detection"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/code_detection_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textColor="@color/textDetection"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/network_detection_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/network_signature"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/code_detection"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/network_detection"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/network_detection_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textColor="@color/textDetection"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tracker_presence_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/network_detection"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textColor="@color/textColorDark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_app_found"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_app_found_tracker"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_presence_title"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/retrieve_app"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_presence_title"/>
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/applications"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tracker_presence_title" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
</layout>
|
|
@ -3,25 +3,11 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
>
|
>
|
||||||
<data/>
|
<data/>
|
||||||
<LinearLayout
|
<TextView
|
||||||
android:gravity="center"
|
android:id="@+id/tracker_name"
|
||||||
android:orientation="horizontal"
|
android:layout_marginTop="5dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_marginBottom="5dp"
|
||||||
android:layout_height="wrap_content">
|
android:textColor="@color/textColorDark"
|
||||||
<TextView
|
android:layout_width="wrap_content"
|
||||||
android:text="●"
|
android:layout_height="wrap_content"/>
|
||||||
android:textColor="@android:color/black"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="10dp"
|
|
||||||
android:layout_marginRight="10dp"
|
|
||||||
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tracker_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</layout>
|
</layout>
|
|
@ -5,6 +5,11 @@
|
||||||
android:id="@+id/action_filter"
|
android:id="@+id/action_filter"
|
||||||
android:icon="@drawable/ic_search"
|
android:icon="@drawable/ic_search"
|
||||||
android:title="@string/menu_action_filter"
|
android:title="@string/menu_action_filter"
|
||||||
app:actionViewClass="android.support.v7.widget.SearchView"
|
app:actionViewClass="android.widget.SearchView"
|
||||||
app:showAsAction="ifRoom|collapseActionView" />
|
app:showAsAction="ifRoom|collapseActionView" />
|
||||||
</menu>
|
<item
|
||||||
|
android:id="@+id/action_settings"
|
||||||
|
android:icon="@drawable/ic_settings"
|
||||||
|
android:title="@string/menu_action_settings"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
</menu>
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="108dp"
|
||||||
|
android:layout_height="108dp">
|
||||||
|
<background android:drawable="@mipmap/ic_launcher_background" />
|
||||||
|
<foreground>
|
||||||
|
<inset
|
||||||
|
android:drawable="@mipmap/ic_launcher_foreground"
|
||||||
|
android:inset="16%" />
|
||||||
|
</foreground>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<size
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp" />
|
||||||
|
<solid android:color="#684971" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportHeight="54"
|
||||||
|
android:viewportWidth="54">
|
||||||
|
<path
|
||||||
|
android:fillColor="#fff"
|
||||||
|
android:pathData="m22.6353,26.1025c-4.3263,-1.5231 -6.4894,-3.8295 -6.4894,-6.9192 -0,-2.4369 1.1474,-4.3843 3.4423,-5.8421 2.2949,-1.4578 5.1443,-2.1867 8.5482,-2.1867 3.0964,0 5.556,0.5059 7.3788,1.5176 1.8227,1.0118 2.7341,2.2248 2.7341,3.6391 -0,0.7398 -0.2855,1.3871 -0.8565,1.9419 -0.571,0.5549 -1.2298,0.8323 -1.9765,0.8323 -1.2298,0 -2.24,-0.8486 -3.0306,-2.5457 -1.098,-2.3499 -2.7451,-3.5248 -4.9412,-3.5249 -1.7349,0 -3.1624,0.5657 -4.2823,1.6972 -1.12,1.1315 -1.68,2.7089 -1.68,4.7325 -0,3.9818 2.0753,5.9727 6.2259,5.9727 0.4392,0 0.9443,-0.0435 1.5153,-0.1305 0.9882,-0.1305 1.7568,-0.1958 2.3059,-0.1958 1.3396,0 2.0094,0.3808 2.0094,1.1423 -0,0.8486 -0.6808,1.2729 -2.0424,1.2729 -0.4832,0 -1.2079,-0.0761 -2.1741,-0.2285 -0.7247,-0.1305 -1.2847,-0.1958 -1.68,-0.1958 -4.3922,0 -6.5882,2.2194 -6.5882,6.6581 -0,2.1541 0.5819,3.8893 1.7459,5.2057 1.1639,1.3164 2.789,1.9746 4.8753,1.9746 2.6133,0 4.3482,-1.3381 5.2047,-4.0144 0.4392,-1.4143 0.9278,-2.3934 1.4659,-2.9374 0.538,-0.544 1.2572,-0.8159 2.1576,-0.8159 0.7466,0 1.4219,0.2665 2.0259,0.7996 0.6039,0.5331 0.9059,1.213 0.9059,2.0399 -0,1.98 -1.12,3.6173 -3.36,4.912 -2.24,1.2946 -4.9522,1.9419 -8.1365,1.9419 -3.4918,0 -6.5937,-0.8268 -9.3059,-2.4805 -2.7122,-1.6536 -4.0682,-3.8621 -4.0682,-6.6254 -0,-3.4596 2.6902,-6.0053 8.0706,-7.6372z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="108dp"
|
||||||
|
android:layout_height="108dp">
|
||||||
|
<background android:drawable="@mipmap/ic_launcher_background" />
|
||||||
|
<foreground>
|
||||||
|
<inset
|
||||||
|
android:drawable="@mipmap/ic_launcher_foreground"
|
||||||
|
android:inset="16%" />
|
||||||
|
</foreground>
|
||||||
|
</adaptive-icon>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">شعار التطبيق</string>
|
||||||
|
<string name="trackers_pct">المتعقِّبون:</string>
|
||||||
|
<string name="permissions_pct">التصريحات:</string>
|
||||||
|
<string name="trackers">المتعقِّبون</string>
|
||||||
|
<string name="permissions">التصريحات</string>
|
||||||
|
<string name="network_error">الشبكة غير متوفرة</string>
|
||||||
|
<string name="not_connected">لا يوجد اتصال بشبكة الانترنت</string>
|
||||||
|
<string name="json_error">خطأ JSON</string>
|
||||||
|
<string name="installed">النسخة المثبتة:</string>
|
||||||
|
<string name="report_version">النسخة المُجرَّبة:</string>
|
||||||
|
<string name="no_trackers">لم نعثر على أي متعقِّب قمنا بتجريبه</string>
|
||||||
|
<string name="no_permissions">هذا التطبيق لا يتطلب أية تصريحات</string>
|
||||||
|
<string name="tested">%1$s%2$sليس هناك أي تقرير عن النسخة المثبتة، إنّ البيانات المعروضة مستمدة مِن نسخة أخرى قديمة لنفس التطبيق</string>
|
||||||
|
<string name="analysed">لم يتم بعد فحص هذا التطبيق بواسطة Exodus Privacy.</string>
|
||||||
|
<string name="no_package_manager">يبدو أنّ نظام جهازك لا يسمح بالوصول إلى قائمة التطبيقات المثبة.</string>
|
||||||
|
<string name="no_app_found">يبدو أنه ليس لديك أي تطبيقات مثبتة من المصدر الذي نقوم باختباره (متجر Google Play أو F-Droid).</string>
|
||||||
|
<string name="get_reports_connection">جلب التطبيقات: في انتظار الاتصال بالخادم</string>
|
||||||
|
<string name="get_reports">جارٍ جلب التطبيقات</string>
|
||||||
|
<string name="parse_application">فحص التطبيقات:</string>
|
||||||
|
<string name="parse_trackers">فحص المتعقّبون:</string>
|
||||||
|
<string name="get_trackers_connection">جلب المتعقّبين: في انتظار الاتصال بالخادم</string>
|
||||||
|
<string name="get_trackers">جارٍ جلب المُتعقّبين</string>
|
||||||
|
<string name="no_settings">ليس لدى هذا التطبيق إعدادات</string>
|
||||||
|
<string name="logo">شعار تطبيق %1</string>
|
||||||
|
<string name="created_by">أنشأه</string>
|
||||||
|
<string name="created_date">تم إنشاء التقرير في</string>
|
||||||
|
<string name="and_updated">وتحديثه في</string>
|
||||||
|
<string name="view_on_exodus">رؤيته على εxodus ←</string>
|
||||||
|
<string name="view_on_google_play">رؤيته على متجر غوغل للتطبيقات ←</string>
|
||||||
|
<string name="view_on_fdroid">رؤيته على F-Droid ←</string>
|
||||||
|
<string name="downloads">تنزيلات</string>
|
||||||
|
<string name="code_signature_found">لقد وجدنا توقيع الرمز البرمجي للمتعقبين التاليين في التطبيق:</string>
|
||||||
|
<string name="code_signature_not_found">لم نجد توقيع الرمز البرمجي لأي متتبع نعرفه في التطبيق.</string>
|
||||||
|
<string name="code_permission_found">لقد وجدنا التصريحات التالية في التطبيق:</string>
|
||||||
|
<string name="code_permission_not_found">هذا التطبيق لا يطلب صلاحيات.</string>
|
||||||
|
<string name="tracker_infos">المتعقب هو جزء من برنامج يهدف إلى جمع البيانات عنك أو عن استخداماتك. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">تعرف على المزيد…</a></string>
|
||||||
|
<string name="permission_infos">التصريحات هي إجراءات يمكن أن يقوم بها التطبيق على هاتفك. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">اعرف المزيد…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">تشير الأيقونة <font color="red"><b>!</b></font> إلى درجات \'خطير\' أو \'خاص\' حسب تصنيف <a href="https://developer.android.com/guide/topics/permissions/overview">درجات الأمان لدى غوغل.</a></string>
|
||||||
|
<string name="tracker_web_page">صفحة الويب للمتعقب ←</string>
|
||||||
|
<string name="detection_rules">قواعد الكشف</string>
|
||||||
|
<string name="code_signature">قاعدة كشف الرمز:</string>
|
||||||
|
<string name="network_signature">القاعدة الشبكية للإكتشاف:</string>
|
||||||
|
<string name="tracker_presence">موجود في %d من تطبيقاتك</string>
|
||||||
|
<string name="tracker_presence_in">موجود في:</string>
|
||||||
|
<string name="no_app_found_tracker">يبدو أن هذا المتعقب غير موجود في تطبيقاتك</string>
|
||||||
|
<string name="source">المصدر: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">عامل التصفية</string>
|
||||||
|
<string name="menu_action_settings">إعدادات التطبيق</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">Logo de l\'aplicació</string>
|
||||||
|
<string name="trackers_pct">Rastrejadors:</string>
|
||||||
|
<string name="permissions_pct">Permisos:</string>
|
||||||
|
<string name="trackers">Rastrejadors</string>
|
||||||
|
<string name="permissions">Permisos</string>
|
||||||
|
<string name="network_error">Xarxa no disponible</string>
|
||||||
|
<string name="not_connected">No hi ha connexió a Internet</string>
|
||||||
|
<string name="json_error">Error JSON</string>
|
||||||
|
<string name="installed">Versió instal·lada:</string>
|
||||||
|
<string name="report_version">Versió que s\'ha provat:</string>
|
||||||
|
<string name="no_trackers">L\'aplicació podria contenir rastrejadors que encara no ho coneixem.</string>
|
||||||
|
<string name="no_permissions">Aquesta aplicació no requereix cap permís.</string>
|
||||||
|
<string name="tested">No hi ha cap informe per a la versió instal·lada (%1$s), la informació mostrada es basa en un altre versió (%2$s)</string>
|
||||||
|
<string name="analysed">Aquesta aplicació no ha estat analitzada encara per Exodus Privacy.</string>
|
||||||
|
<string name="no_package_manager">Sembla que el sistema no permet l’accés a la llista d’aplicacions instal·lades.</string>
|
||||||
|
<string name="no_app_found">Sembla que no teniu cap aplicació instal·lada des de la font que provem (Google Play Store o F-Droid).</string>
|
||||||
|
<string name="get_reports_connection">S\'estan obtenint les aplicacions: s\'està esperant la connexió del servidor </string>
|
||||||
|
<string name="get_reports">S\'estan obtenint les aplicacions</string>
|
||||||
|
<string name="parse_application">S\'estan processant les aplicacions:</string>
|
||||||
|
<string name="parse_trackers">S\'estan processant els rastrejadors:</string>
|
||||||
|
<string name="get_trackers_connection">S\'estan obtenint els rastrejadors: s\'està esperant la connexió del servidor</string>
|
||||||
|
<string name="get_trackers">S\'estan obtenint els rastrejadors</string>
|
||||||
|
<string name="no_settings">Aquesta aplicació no té configuració</string>
|
||||||
|
<string name="logo">Logo de l\'aplicació %1</string>
|
||||||
|
<string name="created_by">Creat per</string>
|
||||||
|
<string name="created_date">S\'ha creat aquest informe el </string>
|
||||||
|
<string name="and_updated">i actualitzat el</string>
|
||||||
|
<string name="view_on_exodus">Vegueu al εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Vegueu al Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">Vegeu a F-Droid ➤</string>
|
||||||
|
<string name="downloads">baixades</string>
|
||||||
|
<string name="code_signature_found">Hem trobat la signatura del codi dels següents rastrejadors a l\'aplicació:</string>
|
||||||
|
<string name="code_signature_not_found">No hem trobat cap signatura de codi de cap rastrejador que coneguem a l\'aplicació.</string>
|
||||||
|
<string name="code_permission_found">Hem trobat els permisos següents a l\'aplicació:</string>
|
||||||
|
<string name="code_permission_not_found">Aquesta aplicació no requereix cap permís.</string>
|
||||||
|
<string name="tracker_infos">Un rastrejador és una peça de programari destinat a recollir dades sobre tu o el teu comportament. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Més informació…</a></string>
|
||||||
|
<string name="permission_infos">Els permisos són accions que l\'aplicació pot fer al telèfon. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Més informació…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">La icona <font color="red"><b>!</b></font> indica nivell «perillós» o «especial» segons <a href="https://developer.android.com/guide/topics/permissions/overview">els nivells de protecció de Google.</a></string>
|
||||||
|
<string name="tracker_web_page">Pàgina web del rastrejador ➤</string>
|
||||||
|
<string name="detection_rules">Regles de detecció</string>
|
||||||
|
<string name="code_signature">Regla de detecció de codi:</string>
|
||||||
|
<string name="network_signature">Regla de detecció de xarxa:</string>
|
||||||
|
<string name="tracker_presence">Present en %d de les vostres aplicacions</string>
|
||||||
|
<string name="tracker_presence_in">Present en:</string>
|
||||||
|
<string name="no_app_found_tracker">Aquest rastrejador no sembla estar present en les vostres aplicacions</string>
|
||||||
|
<string name="source">Font: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">Filtre</string>
|
||||||
|
<string name="menu_action_settings">Paràmetres de l\'aplicació</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">App Logo</string>
|
||||||
|
<string name="trackers_pct">Tracker:</string>
|
||||||
|
<string name="permissions_pct">Berechtigungen:</string>
|
||||||
|
<string name="trackers">Tracker</string>
|
||||||
|
<string name="permissions">Berechtigungen</string>
|
||||||
|
<string name="network_error">Netzwerk nicht verfügbar</string>
|
||||||
|
<string name="not_connected">Keine Verbindung</string>
|
||||||
|
<string name="json_error">JSON Fehler</string>
|
||||||
|
<string name="installed">Installierte Version: </string>
|
||||||
|
<string name="report_version">Getestete Version: </string>
|
||||||
|
<string name="no_trackers">Diese Anwendung könnte Tracker, die uns unbekannt sind, enthalten.</string>
|
||||||
|
<string name="no_permissions">Diese App braucht keine Berechtigungen</string>
|
||||||
|
<string name="tested">Es gibt keinen Bericht für die installierte Version (%1$s), die gezeigte Informationen basieren auf einer anderen Version (%2$s)</string>
|
||||||
|
<string name="analysed">Diese App wurde von Exodus Privacy noch nicht analysiert.</string>
|
||||||
|
<string name="no_package_manager">Ihr System scheint den Zugriff auf die Appliste nicht zu erlauben.</string>
|
||||||
|
<string name="no_app_found">Es scheint, dass keine App aus den Quellen, die wir prüfen (Google Play Store und F-Droid), installiert ist.</string>
|
||||||
|
<string name="get_reports_connection">App erhalten: Warte auf Antwort des Servers</string>
|
||||||
|
<string name="get_reports">App erhalten</string>
|
||||||
|
<string name="parse_application">Untersuchung der App:</string>
|
||||||
|
<string name="parse_trackers">Untersuchung der Tracker:</string>
|
||||||
|
<string name="get_trackers_connection">Tracker erhalten: Warte auf Antwort des Servers</string>
|
||||||
|
<string name="get_trackers">Tracker erhalten</string>
|
||||||
|
<string name="no_settings">Diese App hat keine Einstellungen</string>
|
||||||
|
<string name="logo">%1 Anwendungslogo</string>
|
||||||
|
<string name="created_by">Erstellt von</string>
|
||||||
|
<string name="created_date">Bericht erstellt am</string>
|
||||||
|
<string name="and_updated">und zuletzt aktualisiert am</string>
|
||||||
|
<string name="view_on_exodus">Siehe auf εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Siehe auf Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">Siehe auf F-Droid ➤</string>
|
||||||
|
<string name="downloads">downloads</string>
|
||||||
|
<string name="code_signature_found">Wir haben die Code-Signatur der folgenden Tracker in der Anwendung gefunden:</string>
|
||||||
|
<string name="code_signature_not_found">Wir haben keine Code-Signatur irgendeines Trackers in der App gefunden.</string>
|
||||||
|
<string name="code_permission_found">Wir haben die folgenden Berechtigungen in der Anwendung gefunden:</string>
|
||||||
|
<string name="code_permission_not_found">Diese App erfordert keine Berechtigungen.</string>
|
||||||
|
<string name="tracker_infos">Ein Tracker ist eine Software, die Daten über Sie oder Ihre Nutzung erfassen soll. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Erfahre mehr…</a></string>
|
||||||
|
<string name="permission_infos">Berechtigungen sind Aktionen, die die Anwendung auf Ihrem Telefon ausführen kann. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Mehr erfahren…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">Das Symbol <font color="red"><b>!</b></font> zeigt eine \'Gefährliche\' oder \'Spezial\' Stufe nach <a href="https://developer.android.com/guide/topics/permissions/overview">Googles Schutzstufen an.</a></string>
|
||||||
|
<string name="tracker_web_page">Tracker-Webseite ➤</string>
|
||||||
|
<string name="detection_rules">Erkennungsregeln</string>
|
||||||
|
<string name="code_signature">Code-Erkennungsregel:</string>
|
||||||
|
<string name="network_signature">Netzwerkerkennungsregel:</string>
|
||||||
|
<string name="tracker_presence">Vorhanden in %d der installierten Apps</string>
|
||||||
|
<string name="tracker_presence_in">Vorhanden in:</string>
|
||||||
|
<string name="no_app_found_tracker">Dieser Tracker scheint in den installierten Apps nicht vorhanden zu sein</string>
|
||||||
|
<string name="source">Quelle: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">Filter</string>
|
||||||
|
<string name="menu_action_settings">Anwendungs-Einstellungen</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">Λογότυπο Εφαρμογής</string>
|
||||||
|
<string name="trackers_pct">Trackers:</string>
|
||||||
|
<string name="permissions_pct">Άδειες:</string>
|
||||||
|
<string name="trackers">Trackers</string>
|
||||||
|
<string name="permissions">Άδειες</string>
|
||||||
|
<string name="network_error">Το δίκτυο δεν είναι διαθέσιμο</string>
|
||||||
|
<string name="not_connected">Χωρίς σύνδεση στο Διαδίκτυο</string>
|
||||||
|
<string name="json_error">Σφάλμα JSON</string>
|
||||||
|
<string name="installed">Εγκατεστημένη Έκδοση: </string>
|
||||||
|
<string name="report_version">Δοκιμαστική έκδοση: </string>
|
||||||
|
<string name="no_trackers">Η εφαρμογή μπορεί να περιέχει tracker(s) που δεν γνωρίζουμε ακόμα.</string>
|
||||||
|
<string name="no_permissions">Αυτή η εφαρμογή δεν απαιτεί δικαιώματα.</string>
|
||||||
|
<string name="tested">Δεν υπάρχει αναφορά για την εγκατεστημένη έκδοση (%1$s), οι πληροφορίες που εμφανίζονται βασίζονται σε άλλη (%2$s) έκδοση</string>
|
||||||
|
<string name="analysed">Αυτή η εφαρμογή δεν έχει αναλυθεί ακόμη από το Exodus Privacy.</string>
|
||||||
|
<string name="no_package_manager">Φαίνεται ότι το σύστημα σας δεν επιτρέπει την πρόσβαση στη λίστα των εγκατεστημένων εφαρμογών.</string>
|
||||||
|
<string name="no_app_found">Φαίνεται ότι δεν έχετε εγκαταστήσει εφαρμογές, από την πηγές που δοκιμάζουμε (Google Play store ή F-Droid).</string>
|
||||||
|
<string name="get_reports_connection">Λήψη αναφοράς εφαρμογών: Αναμονή για σύνδεση διακομιστή</string>
|
||||||
|
<string name="get_reports">Λήψη αναφοράς εφαρμογών</string>
|
||||||
|
<string name="parse_application">Επεξεργασία Εφαρμογών:</string>
|
||||||
|
<string name="parse_trackers">Επεξεργασία των Trackers:</string>
|
||||||
|
<string name="get_trackers_connection">Λήψη αναφοράς των trackers: Αναμονή για σύνδεση διακομιστή</string>
|
||||||
|
<string name="get_trackers">Λήψη αναφοράς των trackers</string>
|
||||||
|
<string name="no_settings">Αυτή η εφαρμογή δεν έχει ρυθμίσεις</string>
|
||||||
|
<string name="logo">%1 Λογότυπο Εφαρμογής</string>
|
||||||
|
<string name="created_by">Δημιουργήθηκε από</string>
|
||||||
|
<string name="created_date">Η αναφορά δημιουργήθηκε στις</string>
|
||||||
|
<string name="and_updated">και ενημερώθηκε στις</string>
|
||||||
|
<string name="view_on_exodus">Δείτε στο εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Δείτε στο Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">Δείτε στο F-Droid ➤</string>
|
||||||
|
<string name="downloads">λήψεις</string>
|
||||||
|
<string name="code_signature_found">Εχουμε βρει υπογραφές κώδικα των παρακάτω trackers στην εφαρμογή:</string>
|
||||||
|
<string name="code_signature_not_found">Δεν έχουμε βρει υπογραφή κώδικα σε κάποιο tracker που γνωρίζουμε στην εφαρμογή.</string>
|
||||||
|
<string name="code_permission_found">Βρήκαμε τα ακόλουθα δικαιώματα στην εφαρμογή:</string>
|
||||||
|
<string name="code_permission_not_found">Αυτή η εφαρμογή δεν απαιτεί δικαιώματα.</string>
|
||||||
|
<string name="tracker_infos">Το tracker είναι ένα λογισμικό που προορίζεται για να συλλέγει δεδομένα για εσάς, ή για τις ενέργειες που κάνετε. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Μάθετε περισσότερα…</a></string>
|
||||||
|
<string name="permission_infos">Οι άδειες, είναι οι ενέργειες που μπορεί εκτελέσει μια εφαρμογή στο τηλέφωνό σας. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Μάθετε περισσότερα…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">Το εικονίδιο <font color="red"><b>!</b></font> υποδεικνύει ένα «Επικίνδυνο» ή «Ειδικό» επίπεδο, σύμφωνα με τα <a href="https://developer.android.com/guide/topics/permissions/overview">Επίπεδα προστασίας της Google.</a></string>
|
||||||
|
<string name="tracker_web_page">Ιστοσελίδα του Tracker ➤</string>
|
||||||
|
<string name="detection_rules">Κανόνες Ανίχνευσης</string>
|
||||||
|
<string name="code_signature">Κανόνας ανίχνευσης κώδικα:</string>
|
||||||
|
<string name="network_signature">Κανόνας ανίχνευσης δικτύου:</string>
|
||||||
|
<string name="tracker_presence">Παρών σε %d από τις εφαρμογές σας</string>
|
||||||
|
<string name="tracker_presence_in">Παρών σε:</string>
|
||||||
|
<string name="no_app_found_tracker">Αυτό το tracker φαίνεται να μην υπάρχει στις εφαρμογές σας</string>
|
||||||
|
<string name="source">Πηγή: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">Φίλτρο</string>
|
||||||
|
<string name="menu_action_settings">Ρυθμίσεις Εφαρμογής</string>
|
||||||
|
</resources>
|
|
@ -1,26 +1,52 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Exodus Privacy</string>
|
|
||||||
<string name="app_logo">Application Logo</string>
|
<string name="app_logo">Application Logo</string>
|
||||||
<string name="trackers">Pisteurs :</string>
|
<string name="trackers_pct">Pisteurs :</string>
|
||||||
<string name="permissions">Autorisations :</string>
|
<string name="permissions_pct">Autorisations :</string>
|
||||||
|
<string name="trackers">Pisteurs</string>
|
||||||
|
<string name="permissions">Autorisations</string>
|
||||||
<string name="network_error">Réseau indisponible</string>
|
<string name="network_error">Réseau indisponible</string>
|
||||||
<string name="not_connected">Aucune connexion Internet</string>
|
<string name="not_connected">Aucune connexion Internet</string>
|
||||||
<string name="json_error">Erreur JSON</string>
|
<string name="json_error">Erreur JSON</string>
|
||||||
<string name="installed">Version installée : </string>
|
<string name="installed">Version installée : </string>
|
||||||
<string name="report_version">Version testée : </string>
|
<string name="report_version">Version testée : </string>
|
||||||
<string name="no_trackers">Aucun pisteur testé n\'a été trouvé</string>
|
<string name="no_trackers">L’application pourrait contenir un ou plusieurs pisteurs que nous n’avons pas encore identifiés.</string>
|
||||||
<string name="no_permissions">Aucune autorisation n\'est demandée par cette application</string>
|
<string name="no_permissions">Cette application ne demande aucun autorisation.</string>
|
||||||
<string name="tested">Il n\'y a pas de rapport pour la version installée, les informations affichées sont basées sur une autre version (vraisemblablement plus ancienne)</string>
|
<string name="tested">Il n\'y a pas de rapport pour la version installée (%1$s), les informations affichées sont basées sur une autre version (%2$s)</string>
|
||||||
<string name="analysed">Cette application n\'a pas encore été analysée par Exodus Privacy.</string>
|
<string name="analysed">Cette application n\'a pas encore été analysée par Exodus Privacy.</string>
|
||||||
<string name="no_package_manager">Votre système semble ne pas donner accès aux applications installées.</string>
|
<string name="no_package_manager">Votre système semble ne pas donner accès aux applications installées.</string>
|
||||||
<string name="no_app_found">Vous semblez n\'avoir aucune application installée par la source que nous recherchons (Google Play).</string>
|
<string name="no_app_found">Vous semblez n\'avoir aucune application installée par la source que nous recherchons (Google Play ou F-Droid).</string>
|
||||||
<string name="get_reports_connection">Récupération des applications : en attente de connexion au serveur</string>
|
<string name="get_reports_connection">Récupération des applications : en attente de connexion au serveur</string>
|
||||||
<string name="get_reports">Récupération des applications</string>
|
<string name="get_reports">Récupération des applications</string>
|
||||||
<string name="parse_application">Traitement des applications :</string>
|
<string name="parse_application">Traitement des applications :</string>
|
||||||
<string name="parse_trackers">Traitement des pisteurs :</string>
|
<string name="parse_trackers">Traitement des pisteurs :</string>
|
||||||
<string name="get_trackers_connection">Récupération des pisteurs : en attente de connexion au serveur</string>
|
<string name="get_trackers_connection">Récupération des pisteurs : en attente de connexion au serveur</string>
|
||||||
<string name="get_trackers">Récupération des pisteurs</string>
|
<string name="get_trackers">Récupération des pisteurs</string>
|
||||||
|
<string name="no_settings">Cette app n\'a pas de paramêtre</string>
|
||||||
|
<string name="logo">Logo de l\'application %1</string>
|
||||||
|
<string name="created_by">Crée par</string>
|
||||||
|
<string name="created_date">Rapport créé le</string>
|
||||||
|
<string name="and_updated">et mis à jour le</string>
|
||||||
|
<string name="view_on_exodus">Voir sur εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Voir sur Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">Voir sur F-Droid ➤</string>
|
||||||
|
<string name="downloads">téléchargements</string>
|
||||||
|
<string name="code_signature_found">Nous avons trouvé la signature des pisteurs suivants dans cette application : </string>
|
||||||
|
<string name="code_signature_not_found">Nous n’avons pas trouvé la signature de pisteurs que nous connaissons dans l’application. </string>
|
||||||
|
<string name="code_permission_found">Nous avons trouvé les permissions suivantes dans cette application:</string>
|
||||||
|
<string name="code_permission_not_found">Cette application ne demande aucune autorisation.</string>
|
||||||
|
<string name="tracker_infos">Un pisteur est une partie du logiciel dédiée à la collecte de données sur vous et vos usages. <a href="https://reports.exodus-privacy.eu.org/fr/info/trackers/">En savoir plus…</a></string>
|
||||||
|
<string name="permission_infos">Les permissions sont les actions que l\'application peut effectuer sur votre téléphone. <a href="https://reports.exodus-privacy.eu.org/fr/info/permissions/">En savoir plus…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">L\'icône <font color="red"><b>!</b></font> indique un niveau \'Dangereux\' ou \'Spécial\' d\'après les <a href="https://developer.android.com/guide/topics/permissions/overview">niveaux de protection de Google.</a></string>
|
||||||
|
<string name="tracker_web_page">Page web du pisteur ➤</string>
|
||||||
|
<string name="detection_rules">Règles de détection</string>
|
||||||
|
<string name="code_signature">Règle de détection(code):</string>
|
||||||
|
<string name="network_signature">Règle de détection(réseau):</string>
|
||||||
|
<string name="tracker_presence">Présent dans %d de vos applications</string>
|
||||||
|
<string name="tracker_presence_in">Présent dans:</string>
|
||||||
|
<string name="no_app_found_tracker">Ce pisteur ne semble pas être présent dans vos applications</string>
|
||||||
|
<string name="source">Source: %s</string>
|
||||||
|
|
||||||
<!-- Menu -->
|
<!-- Menu -->
|
||||||
<string name="menu_action_filter">Filtrer</string>
|
<string name="menu_action_filter">Filtrer</string>
|
||||||
|
<string name="menu_action_settings">Paramètres de l\'application</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">Logo applicazione</string>
|
||||||
|
<string name="trackers_pct">Tracciatori:</string>
|
||||||
|
<string name="permissions_pct">Autorizzazioni:</string>
|
||||||
|
<string name="trackers">Tracciatori</string>
|
||||||
|
<string name="permissions">Autorizzazioni</string>
|
||||||
|
<string name="network_error">Rete non disponibile</string>
|
||||||
|
<string name="not_connected">Nessuna connessione internet</string>
|
||||||
|
<string name="json_error">Errore JSON</string>
|
||||||
|
<string name="installed">Versione installata: </string>
|
||||||
|
<string name="report_version">Versione testata: </string>
|
||||||
|
<string name="no_trackers">Nessun tracciatore testato trovato</string>
|
||||||
|
<string name="no_permissions">Nessuna autorizzazione richiesta dall\'applicazione</string>
|
||||||
|
<string name="tested">Non ci sono report per la versione installata (%1$s), le informazioni mostrate sono basate su un\'altra (%2$s) versione</string>
|
||||||
|
<string name="analysed">Questa app non è ancora stata analizzata da Exodus Privacy.</string>
|
||||||
|
<string name="no_package_manager">Sembra che il tuo sistema non permetta l\'accesso all\'elenco di app installate.</string>
|
||||||
|
<string name="no_app_found">Sembra che tu non abbia nessuna app installata dalla fonte che testiamo (Google Play store o F-Droid).</string>
|
||||||
|
<string name="get_reports_connection">Rilevazione applicazioni: in attesa della connessione al server</string>
|
||||||
|
<string name="get_reports">Rilevazione applicazioni</string>
|
||||||
|
<string name="parse_application">Elaborazione applicazioni:</string>
|
||||||
|
<string name="parse_trackers">Elaborazione tracciatori:</string>
|
||||||
|
<string name="get_trackers_connection">Rilevazione tracciatori: in attesa della connessione al server</string>
|
||||||
|
<string name="get_trackers">Rilevazione tracker</string>
|
||||||
|
<string name="no_settings">Questa app non ha impostazioni</string>
|
||||||
|
<string name="logo">%1 Logo dell\'applicazione</string>
|
||||||
|
<string name="created_by">Creato da</string>
|
||||||
|
<string name="created_date">Report creato il</string>
|
||||||
|
<string name="and_updated">ae aggiornato il</string>
|
||||||
|
<string name="view_on_exodus">Vedi su εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Vedi su Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">Vedi su F-Droid ➤</string>
|
||||||
|
<string name="downloads">scaricamenti</string>
|
||||||
|
<string name="code_signature_found">Abbiamo trovato i codici di firma dei seguenti tracker nell\'applicazione:</string>
|
||||||
|
<string name="code_signature_not_found">Non abbiamo trovato il codice di firma di alcun tracker che conosciamo nell\'applicazione.</string>
|
||||||
|
<string name="code_permission_found">Abbiamo trovato i permessi seguenti nell\'applicazione:</string>
|
||||||
|
<string name="code_permission_not_found">Questa applicazione non richiede alcun permesso.</string>
|
||||||
|
<string name="tracker_infos">Un tracker è un software destinato a raccogliere dati su di te o sui tuoi utilizzi. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Per saperne di più…</a></string>
|
||||||
|
<string name="permission_infos">Le autorizzazioni sono azioni che l\'applicazione può fare sul tuo telefono. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Per saperne di più…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">L\'icona <font color="red"><b>!</b></font> indica un livello \'Pericoloso\' o \'Speciale\' in base ai <a href="https://developer.android.com/guide/topics/permissions/overview">livelli di protezione di Google.</a></string>
|
||||||
|
<string name="tracker_web_page">Pagina web del tracker ➤</string>
|
||||||
|
<string name="detection_rules">Regole di rilevamento</string>
|
||||||
|
<string name="code_signature">Regola di rilevamento (codice):</string>
|
||||||
|
<string name="network_signature">Regola di rilevamento (rete):</string>
|
||||||
|
<string name="tracker_presence">Presente in %d applicazioni</string>
|
||||||
|
<string name="tracker_presence_in">Presente in:</string>
|
||||||
|
<string name="no_app_found_tracker">Questo tracker non sembra essere presente nelle tue applicazioni</string>
|
||||||
|
<string name="source">Fonte: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">Filtra</string>
|
||||||
|
<string name="menu_action_settings">Impostazioni dell\'applicazione</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_logo">Логотип приложения</string>
|
||||||
|
<string name="trackers_pct">Трекеры:</string>
|
||||||
|
<string name="permissions_pct">Разрешения:</string>
|
||||||
|
<string name="trackers">трекеров</string>
|
||||||
|
<string name="permissions">разрешений</string>
|
||||||
|
<string name="network_error">Сеть недоступна</string>
|
||||||
|
<string name="not_connected">Нет подключения к интернету</string>
|
||||||
|
<string name="json_error">Ошибка JSON</string>
|
||||||
|
<string name="installed">Установленная версия: </string>
|
||||||
|
<string name="report_version">Изученная версия: </string>
|
||||||
|
<string name="no_trackers">Не найдено ни одного известного трекера</string>
|
||||||
|
<string name="no_permissions">Это приложение не запрашивает никаких разрешений</string>
|
||||||
|
<string name="tested">Данные по установленной версии (%1$s) отсутствуют, показана информация на основе изученной (%2$s) версии</string>
|
||||||
|
<string name="analysed">Это приложение ещё не было изучено Exodus Privacy.</string>
|
||||||
|
<string name="no_package_manager">Похоже, ваша система не разрешает доступ к списку установленных приложений.</string>
|
||||||
|
<string name="no_app_found">Похоже, у вас нет приложений, установленных из источника, который мы тестируем (магазин Google Play или F-Droid).</string>
|
||||||
|
<string name="get_reports_connection">Получение приложений: ожидание подключения к серверу</string>
|
||||||
|
<string name="get_reports">Получение приложений</string>
|
||||||
|
<string name="parse_application">Обработка приложений:</string>
|
||||||
|
<string name="parse_trackers">Обработка трекеров:</string>
|
||||||
|
<string name="get_trackers_connection">Получение трекеров: ожидание подключения к серверу</string>
|
||||||
|
<string name="get_trackers">Получение трекеров</string>
|
||||||
|
<string name="no_settings">Это приложение не имеет настроек</string>
|
||||||
|
<string name="logo">Логотип приложения %1</string>
|
||||||
|
<string name="created_by">Создано</string>
|
||||||
|
<string name="created_date">Отчёт создан</string>
|
||||||
|
<string name="and_updated">и обновлено</string>
|
||||||
|
<string name="view_on_exodus">εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">F-Droid ➤</string>
|
||||||
|
<string name="downloads">загрузок</string>
|
||||||
|
<string name="code_signature_found">В приложении обнаружены сигнатуры следующих трекеров:</string>
|
||||||
|
<string name="code_signature_not_found">В приложении не обнаружено сигнатур ни одного известного трекера.</string>
|
||||||
|
<string name="code_permission_found">В приложении обнаружены следующее разрешения:</string>
|
||||||
|
<string name="code_permission_not_found">Приложение не требует никаких разрешений.</string>
|
||||||
|
<string name="tracker_infos">Трекер — это часть приложения, предназначенная для сбора данных о вас или ваших действиях. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Подробнее…</a></string>
|
||||||
|
<string name="permission_infos">Разрешения — это действия, которые приложение сможет выполнять на вашем устройстве. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Подробнее…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">Значок <font color="red"><b>!</b></font> обозначает уровень угрозы «Опасность» или «Особый» в соответствии с <a href="https://developer.android.com/guide/topics/permissions/overview">уровнем защиты Google</a>.</string>
|
||||||
|
<string name="tracker_web_page">Сайт трекера ➤</string>
|
||||||
|
<string name="detection_rules">Определяющие правила</string>
|
||||||
|
<string name="code_signature">Правило обнаружения кода:</string>
|
||||||
|
<string name="network_signature">Правило определения сети:</string>
|
||||||
|
<string name="tracker_presence">Присутствует в %d приложениях</string>
|
||||||
|
<string name="tracker_presence_in">Присутствует в:</string>
|
||||||
|
<string name="no_app_found_tracker">Этот трекер не присутствует в ваших приложениях</string>
|
||||||
|
<string name="source">Источник: %s</string>
|
||||||
|
<!-- Menu -->
|
||||||
|
<string name="menu_action_filter">Фильтр</string>
|
||||||
|
<string name="menu_action_settings">Настройки приложения</string>
|
||||||
|
</resources>
|
|
@ -3,4 +3,19 @@
|
||||||
<color name="colorPrimary">#684971</color>
|
<color name="colorPrimary">#684971</color>
|
||||||
<color name="colorPrimaryDark">#3d2b43</color>
|
<color name="colorPrimaryDark">#3d2b43</color>
|
||||||
<color name="colorAccent">#684971</color>
|
<color name="colorAccent">#684971</color>
|
||||||
|
|
||||||
|
<color name="colorGreen">#6fc384</color>
|
||||||
|
<color name="colorLightRed">#e46772</color>
|
||||||
|
<color name="colorLightYellow">#ffdb66</color>
|
||||||
|
|
||||||
|
<color name="colorLightBlue">#17a2b8</color>
|
||||||
|
<color name="colorYellow">#ffc70f</color>
|
||||||
|
<color name="colorDarkOrange">#ff8c00</color>
|
||||||
|
<color name="colorRed">#e61718</color>
|
||||||
|
|
||||||
|
<color name="colorPurple">#684971</color>
|
||||||
|
<color name="textColorDark">#343A40</color>
|
||||||
|
<color name="textColorDarkLight">#6C757D</color>
|
||||||
|
<color name="textColorWhite">#FFFFFF</color>
|
||||||
|
<color name="textDetection">#E83E8C</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="exodus">9c6106a229bc5f34b5802e5861bcb87d1626617d</string>
|
<string name="exodus">9c6106a229bc5f34b5802e5861bcb87d1626617d</string>
|
||||||
|
<string name="app_title">εxodus</string>
|
||||||
|
<string name="app_name">Exodus</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,26 +1,53 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Exodus Privacy</string>
|
|
||||||
<string name="app_logo">Application Logo</string>
|
<string name="app_logo">Application Logo</string>
|
||||||
<string name="trackers">Trackers:</string>
|
<string name="trackers_pct">Trackers:</string>
|
||||||
<string name="permissions">Permissions:</string>
|
<string name="permissions_pct">Permissions:</string>
|
||||||
|
<string name="trackers">Trackers</string>
|
||||||
|
<string name="permissions">Permissions</string>
|
||||||
<string name="network_error">Network Unavailable</string>
|
<string name="network_error">Network Unavailable</string>
|
||||||
<string name="not_connected">No Internet Connection</string>
|
<string name="not_connected">No Internet Connection</string>
|
||||||
<string name="json_error">JSON Error</string>
|
<string name="json_error">JSON Error</string>
|
||||||
<string name="installed">Installed Version: </string>
|
<string name="installed">Installed Version: </string>
|
||||||
<string name="report_version">Tested Version: </string>
|
<string name="report_version">Tested Version: </string>
|
||||||
<string name="no_trackers">No tested trackers were found</string>
|
<string name="no_trackers">The application could contain tracker(s) we do not know yet.</string>
|
||||||
<string name="no_permissions">No permissions are requested by this application</string>
|
<string name="no_permissions">This application doesn\'t require any permissions.</string>
|
||||||
<string name="tested">There\'s no report for the installed version, informations displayed are based on another (presumably older) version</string>
|
<string name="tested">There\'s no report for the installed version (%1$s), the information displayed is based on another (%2$s) version</string>
|
||||||
<string name="analysed">This app hasn\'t been analysed by Exodus Privacy yet.</string>
|
<string name="analysed">This app hasn\'t been analysed by Exodus Privacy yet.</string>
|
||||||
<string name="no_package_manager">Your system seems doesn\'t provide access to installed apps.</string>
|
<string name="no_package_manager">It appears that your system doesn\'t allow access to the list of installed apps.</string>
|
||||||
<string name="no_app_found">You seems not having any apps installed by source we search for (Google Play).</string>
|
<string name="no_app_found">It appears that you don\'t have any apps installed from the source we test (Google Play store or F-Droid).</string>
|
||||||
<string name="get_reports_connection">Getting applications: Waiting for server connection</string>
|
<string name="get_reports_connection">Getting applications: Waiting for server connection</string>
|
||||||
<string name="get_reports">Getting applications</string>
|
<string name="get_reports">Getting applications</string>
|
||||||
<string name="parse_application">Processing Applications:</string>
|
<string name="parse_application">Processing Applications:</string>
|
||||||
<string name="parse_trackers">Processing Trackers:</string>
|
<string name="parse_trackers">Processing Trackers:</string>
|
||||||
<string name="get_trackers_connection">Getting trackers: Waiting for server connection</string>
|
<string name="get_trackers_connection">Getting trackers: Waiting for server connection</string>
|
||||||
<string name="get_trackers">Getting trackers</string>
|
<string name="get_trackers">Getting trackers</string>
|
||||||
|
<string name="no_settings">This app doesn\'t have settings</string>
|
||||||
|
<string name="logo">%1 Application Logo</string>
|
||||||
|
<string name="created_by">Created By</string>
|
||||||
|
<string name="created_date">Report created on</string>
|
||||||
|
<string name="and_updated">and updated on</string>
|
||||||
|
<string name="view_on_exodus">See on εxodus ➤</string>
|
||||||
|
<string name="view_on_google_play">See on Google Play ➤</string>
|
||||||
|
<string name="view_on_fdroid">See on F-Droid ➤</string>
|
||||||
|
<string name="downloads">downloads</string>
|
||||||
|
<string name="code_signature_found">We have found code signature of the following trackers in the application:</string>
|
||||||
|
<string name="code_signature_not_found">We have not found code signature of any tracker we know in the application.</string>
|
||||||
|
<string name="code_permission_found">We have found the following permissions in the application:</string>
|
||||||
|
<string name="code_permission_not_found">This application doesn\'t require any permissions.</string>
|
||||||
|
<string name="tracker_infos">A tracker is a piece of software meant to collect data about you or your usages. <a href="https://reports.exodus-privacy.eu.org/en/info/trackers/">Learn more…</a></string>
|
||||||
|
<string name="permission_infos">Permissions are actions the application can do on your phone. <a href="https://reports.exodus-privacy.eu.org/en/info/permissions/">Learn more…</a></string>
|
||||||
|
<string name="permission_infos_dangerous">The icon <font color="red"><b>!</b></font> indicates a \'Dangerous\' or \'Special\' level according to <a href="https://developer.android.com/guide/topics/permissions/overview">Google\'s protection levels.</a></string>
|
||||||
|
<string name="tracker_web_page">Tracker web page ➤</string>
|
||||||
|
<string name="detection_rules">Detection Rules</string>
|
||||||
|
<string name="code_signature">Code detection rule:</string>
|
||||||
|
<string name="network_signature">Network detection rule:</string>
|
||||||
|
<string name="tracker_presence">Present in %d of your applications</string>
|
||||||
|
<string name="tracker_presence_in">Present in:</string>
|
||||||
|
<string name="no_app_found_tracker">This tracker seems not be present in your applications</string>
|
||||||
|
<string name="source">Source: %s</string>
|
||||||
|
|
||||||
<!-- Menu -->
|
<!-- Menu -->
|
||||||
<string name="menu_action_filter">Filter</string>
|
<string name="menu_action_filter">Filter</string>
|
||||||
|
<string name="menu_action_settings">Application Settings</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -6,9 +6,10 @@ buildscript {
|
||||||
maven {
|
maven {
|
||||||
url "https://maven.google.com"
|
url "https://maven.google.com"
|
||||||
}
|
}
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
يساعدك Exodus Privacy على معرفة أي مِن المتعقبين والتصريحات المدمجة في التطبيقات المثبتة على جهازك.
|
||||||
|
|
||||||
|
يقوم التطبيق بتحميل التقارير من Exodus Privacy (https://exodus-privacy.eu.org/) ويعرضها عليك تطبيقًا تلو الآخر
|
||||||
|
|
||||||
|
بإمكان التطبيق اكتشاف التطبيقات المثبتة من متجر Google Play فقط.
|
||||||
|
|
||||||
|
الرمز المصدري: https://github.com/Exodus-Privacy/exodus-android-app/
|
|
@ -0,0 +1 @@
|
||||||
|
يُظهِر المتعقّبِين والتصريحات التي تطلبها التطبيقات المثبتة الأخرى
|
|
@ -0,0 +1,7 @@
|
||||||
|
Exodus Privacy us ajuda a saber quins rastrejadors i permisos estan incrustats en les aplicacions instal·lades al vostre dispositiu.
|
||||||
|
|
||||||
|
The app downloads reports from Exodus Privacy (https://exodus-privacy.eu.org/) and shows them to you app by app
|
||||||
|
|
||||||
|
L'aplicació només pot detectar les aplicacions instal·lades des de la botiga Google Play.
|
||||||
|
|
||||||
|
Codi font: https://github.com/Exodus-Privacy/exodus-android-app/
|
|
@ -0,0 +1 @@
|
||||||
|
Mostra els rastrejadors i els permisos de les aplicacions instal·lades
|
|
@ -0,0 +1,7 @@
|
||||||
|
Exodus Privacy hilft Ihnen zu wissen, welche Tracker und Berechtigungen in Apps eingebettet sind, die auf Ihrem Gerät installiert sind.
|
||||||
|
|
||||||
|
Die App lädt Berichte von Exodus Privacy (https://exodus-privacy.eu.org/) herunter und zeigt sie für jede App
|
||||||
|
|
||||||
|
Die App kann nur installierte Apps aus dem Google Play Store erkennen.
|
||||||
|
|
||||||
|
Quellcode: https://github.com/Exodus-Privacy/exodus-android-app/
|
|
@ -0,0 +1 @@
|
||||||
|
Tracker und Berechtigungen anderer installierter Apps anzeigen
|
|
@ -0,0 +1,7 @@
|
||||||
|
Το Exodus Privacy σάς βοηθά να γνωρίζετε ποια trackers και ποια δικαιώματα, βρίσκονται μέσα στις εφαρμογές που είναι εγκατεστημένες στην συσκευή σας.
|
||||||
|
|
||||||
|
Η εφαρμογή κατεβάζει αναφορές από το Exodus Privacy (https://exodus-privacy.eu.org/) και τις εμφανίζει σε κάθε μία απο τις εφαρμογές σας
|
||||||
|
|
||||||
|
Η εφαρμογή μπορεί να εντοπίσει μόνο εφαρμογές που έχουν εγκατασταθεί από το Google Play store.
|
||||||
|
|
||||||
|
Πηγαίος Κώδικας: https://github.com/Exodus-Privacy/exodus-android-app/
|
|
@ -0,0 +1 @@
|
||||||
|
Εμφάνιση ιχνηλατών και αδειών από άλλες εγκατεστημένες εφαρμογές
|
|
@ -0,0 +1,4 @@
|
||||||
|
- speedup navigation (thanks to borsini)
|
||||||
|
- add shortcut to apps settings
|
||||||
|
- add version identifier when app version doesn't match (thanks to tdelmas)
|
||||||
|
- bug fix
|
|
@ -0,0 +1,2 @@
|
||||||
|
- rewrite of report page
|
||||||
|
- bug fix
|
|
@ -0,0 +1,4 @@
|
||||||
|
- Add Trackers Page
|
||||||
|
- Add F-Droid detection Support
|
||||||
|
- bug fix
|
||||||
|
- New Translations (Italian, Russian, Greek, Arabic, German, and Catalan)
|
|
@ -0,0 +1,7 @@
|
||||||
|
Exodus Privacy helps you to know which trackers and permissions are embedded in apps installed on your device.
|
||||||
|
|
||||||
|
The app downloads reports from Exodus Privacy (https://exodus-privacy.eu.org/) and shows them to you app by app
|
||||||
|
|
||||||
|
The app can only detect apps installed from the Google Play store.
|
||||||
|
|
||||||
|
Source Code: https://github.com/Exodus-Privacy/exodus-android-app/
|
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 194 KiB |
After Width: | Height: | Size: 129 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 158 KiB |
|
@ -0,0 +1 @@
|
||||||
|
Show trackers and permissions from other installed apps
|
|
@ -0,0 +1,4 @@
|
||||||
|
- Amélioration de la vitesse de navigation (grâce à borsini)
|
||||||
|
- Ajout d'un raccourci vers les paramètres des applications
|
||||||
|
- Ajout du numéro de version lorsque la version de l'application ne correspond pas (grâce à tdelmas)
|
||||||
|
- Correction de bug
|
|
@ -0,0 +1,2 @@
|
||||||
|
- Refonte de la page des rapports
|
||||||
|
- Correction de bug
|
|
@ -0,0 +1,4 @@
|
||||||
|
- Ajout de la page des pisteurs
|
||||||
|
- Ajout de la détection pour F-Droid
|
||||||
|
- Correction de bug
|
||||||
|
- Nouvelles Traductions (Italien, Russe, Grec , Arabe, Allemand et Catalan)
|
|
@ -0,0 +1,7 @@
|
||||||
|
Exodus Privacy vous aide à savoir quels sont les pisteurs et permissions embarqués dans les applications installées sur votre smartphone.
|
||||||
|
|
||||||
|
L'application télécharge les rapports d'Exodus Privacy (https://exodus-privacy.eu.org/) et vous les montre application par application.
|
||||||
|
|
||||||
|
L'application ne peut détecter que les applications installées depuis le Google Play Store.
|
||||||
|
|
||||||
|
Code source: https://github.com/Exodus-Privacy/exodus-android-app/
|
After Width: | Height: | Size: 206 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 165 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 159 KiB |
|
@ -0,0 +1 @@
|
||||||
|
Montre les pisteurs et permissions des applications installées
|
|
@ -0,0 +1,7 @@
|
||||||
|
Exodus Privacy ti aiuta a sapere quali tracker e permessi sono incorporati nelle applicazioni installate sul tuo smartphone.
|
||||||
|
|
||||||
|
L'app scarica i report da Exodus Privacy (https://exodus-privacy.eu.org/) e li mostra all'app per app
|
||||||
|
|
||||||
|
L'applicazione può rilevare solo le applicazioni installate dal Google Play store.
|
||||||
|
|
||||||
|
Codice sorgente: https://github.com/Exodus-Privacy/exodus-android-app/
|