Compare commits
14 Commits
3d1320eeb9
...
90848c678a
Author | SHA1 | Date |
---|---|---|
Thomas | 90848c678a | |
Thomas | 6b5631bb43 | |
Thomas | 2f531d7d24 | |
Thomas | e3f2325d00 | |
Thomas | 3d5b4fd04f | |
Thomas | 7d4d2533ac | |
Thomas | c40afdf348 | |
Thomas | 20f2e8412f | |
Thomas | 9d330bf07f | |
Thomas | cae158d489 | |
Thomas | efe9a88209 | |
Thomas | 3bf596f1cf | |
Thomas | 7e6e1fcff6 | |
Thomas | 2a091043c6 |
|
@ -28,20 +28,56 @@ android {
|
|||
}
|
||||
|
||||
productFlavors {
|
||||
exodus {
|
||||
exodus_google {
|
||||
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
||||
buildConfigField "boolean", "amal", "false"
|
||||
}
|
||||
amal {
|
||||
amal_google {
|
||||
applicationId "app.fedilab.amal"
|
||||
buildConfigField "boolean", "amal", "true"
|
||||
}
|
||||
fedilab_google {
|
||||
applicationId "app.fedilab.exodusprivacy"
|
||||
buildConfigField "boolean", "amal", "false"
|
||||
}
|
||||
exodus_fdroid {
|
||||
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
||||
buildConfigField "boolean", "amal", "false"
|
||||
}
|
||||
amal_fdroid {
|
||||
applicationId "app.fedilab.amal"
|
||||
buildConfigField "boolean", "amal", "true"
|
||||
}
|
||||
fedilab_fdroid {
|
||||
applicationId "app.fedilab.exodusprivacy"
|
||||
buildConfigField "boolean", "amal", "false"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
exodus {
|
||||
exodus_google {
|
||||
res.srcDirs = ['src/main/res', 'src/exodus/res']
|
||||
manifest.srcFile 'src/google/AndroidManifest.xml'
|
||||
}
|
||||
amal {
|
||||
fedilab_google {
|
||||
res.srcDirs = ['src/main/res', 'src/fedilab/res']
|
||||
manifest.srcFile 'src/google/AndroidManifest.xml'
|
||||
}
|
||||
amal_google {
|
||||
res.srcDirs = ['src/main/res', 'src/amal/res']
|
||||
manifest.srcFile 'src/google/AndroidManifest.xml'
|
||||
}
|
||||
exodus_fdroid {
|
||||
res.srcDirs = ['src/main/res', 'src/exodus/res']
|
||||
manifest.srcFile 'src/fdroid/AndroidManifest.xml'
|
||||
}
|
||||
fedilab_fdroid {
|
||||
res.srcDirs = ['src/main/res', 'src/fedilab/res']
|
||||
manifest.srcFile 'src/fdroid/AndroidManifest.xml'
|
||||
}
|
||||
amal_fdroid {
|
||||
res.srcDirs = ['src/main/res', 'src/amal/res']
|
||||
manifest.srcFile 'src/fdroid/AndroidManifest.xml'
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<color name="colorPrimary">#005e8b</color>
|
||||
<color name="colorPrimaryDark">#3d2b43</color>
|
||||
<color name="colorAccent">#007bff</color>
|
||||
|
||||
<color name="percent">#77005e8b</color>
|
||||
<color name="colorGreen">#6fc384</color>
|
||||
<color name="colorLightRed">#e46772</color>
|
||||
<color name="colorLightYellow">#ffdb66</color>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<color name="colorPrimary">#684971</color>
|
||||
<color name="colorPrimaryDark">#3d2b43</color>
|
||||
<color name="colorAccent">#3d2b43</color>
|
||||
<color name="percent">#77684971</color>
|
||||
|
||||
<color name="colorGreen">#6fc384</color>
|
||||
<color name="colorLightRed">#e46772</color>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.eu.exodus_privacy.exodusprivacy">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
</manifest>
|
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,27 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="1.48"
|
||||
android:scaleY="1.48"
|
||||
android:translateX="14.04"
|
||||
android:translateY="14.04">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#1976D2"
|
||||
android:pathData="M2.1737,27a24.8263,24.5976 0,1 0,49.6526 0a24.8263,24.5976 0,1 0,-49.6526 0z"
|
||||
android:strokeWidth="0.0297731"
|
||||
android:strokeColor="#00000000" />
|
||||
<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:strokeWidth="0.03275258"
|
||||
android:strokeAlpha="1"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeLineCap="butt"
|
||||
android:strokeLineJoin="miter" />
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="100dp"
|
||||
android:height="100dp"
|
||||
android:viewportWidth="54"
|
||||
android:viewportHeight="54">
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#1976D2"
|
||||
android:pathData="M2.1737,27a24.8263,24.5976 0,1 0,49.6526 0a24.8263,24.5976 0,1 0,-49.6526 0z"
|
||||
android:strokeWidth="0.0297731"
|
||||
android:strokeColor="#00000000" />
|
||||
<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:strokeWidth="0.03275258"
|
||||
android:strokeAlpha="1"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeLineCap="butt"
|
||||
android:strokeLineJoin="miter" />
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#1976D2</color>
|
||||
<color name="colorPrimaryDark">#0D47A1</color>
|
||||
<color name="colorAccent">#64B5F6</color>
|
||||
<color name="percent">#771976D2</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>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="exodus">9c6106a229bc5f34b5802e5861bcb87d1626617d</string>
|
||||
<string name="app_title">εxodus</string>
|
||||
<string name="app_name">Exodus (test)</string>
|
||||
</resources>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#1976D2</color>
|
||||
</resources>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.eu.exodus_privacy.exodusprivacy">
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
|
@ -3,8 +3,10 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.eu.exodus_privacy.exodusprivacy">
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
@ -14,6 +16,7 @@
|
|||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
android:largeHeap="true">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize">
|
||||
|
|
|
@ -48,8 +48,6 @@ public class CheckAppActivity extends AppCompatActivity implements NetworkListen
|
|||
|
||||
private static final Pattern fdroidRegex = Pattern.compile("https?://f-droid\\.org/([\\w-]+/)?packages/([\\w.-]+)");
|
||||
private static final Pattern googleRegex = Pattern.compile("https?://play\\.google\\.com/store/apps/details\\?id=([\\w.-]+)");
|
||||
private String app_id;
|
||||
|
||||
ArrayList<Updatable> fragments;
|
||||
AppCheckActivityBinding binding;
|
||||
TrackerListAdapter.OnTrackerClickListener onTrackerClickListener = id -> {
|
||||
|
@ -62,6 +60,7 @@ public class CheckAppActivity extends AppCompatActivity implements NetworkListen
|
|||
.addToBackStack(null)
|
||||
.commit();
|
||||
};
|
||||
private String app_id;
|
||||
private TrackerListAdapter.OnTrackerClickListener trackerClickListener;
|
||||
|
||||
@Override
|
||||
|
@ -105,10 +104,11 @@ public class CheckAppActivity extends AppCompatActivity implements NetworkListen
|
|||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(CheckAppActivity.this);
|
||||
dialogBuilder.setTitle(getString(R.string.app_not_analyzed_title));
|
||||
dialogBuilder.setMessage(getString(R.string.app_not_analyzed));
|
||||
//noinspection RedundantSuppression
|
||||
dialogBuilder.setPositiveButton(R.string.submit, (dialog, id) -> {
|
||||
Uri uri;
|
||||
//noinspection ConstantConditions
|
||||
if (BuildConfig.FLAVOR.equals("exodus")) {
|
||||
if (!BuildConfig.amal) {
|
||||
uri = Uri.parse("https://reports.exodus-privacy.eu.org/analysis/submit/#" + app_id);
|
||||
} else {
|
||||
uri = Uri.parse("https://exodus.phm.education.gouv.fr/analysis/submit/#" + app_id);
|
||||
|
|
|
@ -33,12 +33,18 @@ import android.view.inputmethod.InputMethodManager;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
||||
|
@ -47,6 +53,7 @@ import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
|||
import org.eu.exodus_privacy.exodusprivacy.databinding.MainBinding;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.ComputeAppList;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.HomeFragment;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.MyTrackersFragment;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.ReportFragment;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.TrackerFragment;
|
||||
import org.eu.exodus_privacy.exodusprivacy.fragments.Updatable;
|
||||
|
@ -65,8 +72,20 @@ public class MainActivity extends AppCompatActivity {
|
|||
private Menu toolbarMenu;
|
||||
private String packageName;
|
||||
private MainBinding binding;
|
||||
private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
|
||||
= item -> {
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.navigation_apps) {
|
||||
binding.viewpager.setCurrentItem(0);
|
||||
} else if (itemId == R.id.navigation_analytics) {
|
||||
binding.viewpager.setCurrentItem(1);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
private ApplicationListAdapter.OnAppClickListener onAppClickListener;
|
||||
private TrackerListAdapter.OnTrackerClickListener onTrackerClickListener;
|
||||
private String previousQuery = "";
|
||||
private HomeFragment home;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -102,7 +121,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
for (Updatable updatable : fragments) {
|
||||
updatable.onUpdateComplete();
|
||||
}
|
||||
Snackbar bar = Snackbar.make(mainBinding.fragmentContainer, error, Snackbar.LENGTH_LONG);
|
||||
Snackbar bar = Snackbar.make(mainBinding.viewpager, error, Snackbar.LENGTH_LONG);
|
||||
bar.show();
|
||||
});
|
||||
}
|
||||
|
@ -113,20 +132,56 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
};
|
||||
|
||||
TrackerListAdapter.OnTrackerClickListener onTrackerClickListener = id -> {
|
||||
setSupportActionBar(binding.toolbar);
|
||||
binding.navView.inflateMenu(R.menu.bottom_nav_menu);
|
||||
binding.navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
|
||||
|
||||
|
||||
binding.viewpager.setOffscreenPageLimit(2);
|
||||
|
||||
|
||||
binding.viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
MenuItem item = binding.navView.getMenu().getItem(position);
|
||||
binding.navView.setSelectedItemId(item.getItemId());
|
||||
if (binding.fragmentContainer.getVisibility() == View.VISIBLE) {
|
||||
while (fragments.size() > 0) {
|
||||
getSupportFragmentManager().popBackStack();
|
||||
fragments.remove(fragments.size() - 1);
|
||||
}
|
||||
binding.fragmentContainer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
onTrackerClickListener = id -> {
|
||||
TrackerFragment tracker = TrackerFragment.newInstance(id);
|
||||
tracker.setOnAppClickListener(onAppClickListener);
|
||||
fragments.add(tracker);
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
binding.fragmentContainer.setVisibility(View.VISIBLE);
|
||||
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, tracker)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
};
|
||||
|
||||
|
||||
onAppClickListener = (vm) -> {
|
||||
try {
|
||||
|
||||
PackageManager pm = getPackageManager();
|
||||
PackageInfo packageInfo = pm.getPackageInfo(vm.packageName, PackageManager.GET_PERMISSIONS);
|
||||
ReportFragment report = ReportFragment.newInstance(pm, vm, packageInfo, onTrackerClickListener);
|
||||
|
@ -137,7 +192,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
.replace(R.id.fragment_container, report)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
|
||||
binding.fragmentContainer.setVisibility(View.VISIBLE);
|
||||
packageName = packageInfo.packageName;
|
||||
|
||||
searchView.clearFocus();
|
||||
|
@ -145,22 +200,18 @@ public class MainActivity extends AppCompatActivity {
|
|||
(toolbarMenu.findItem(R.id.action_filter)).collapseActionView();
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(mainBinding.fragmentContainer.getWindowToken(), 0);
|
||||
imm.hideSoftInputFromWindow(mainBinding.viewpager.getWindowToken(), 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
|
||||
HomeFragment home = new HomeFragment();
|
||||
home = new HomeFragment();
|
||||
fragments.add(home);
|
||||
home.setNetworkListener(networkListener);
|
||||
home.setOnAppClickListener(onAppClickListener);
|
||||
|
||||
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
transaction.replace(R.id.fragment_container, home)
|
||||
.commit();
|
||||
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
|
||||
binding.viewpager.setAdapter(mPagerAdapter);
|
||||
home.startRefresh();
|
||||
}
|
||||
|
||||
|
@ -215,12 +266,15 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
});
|
||||
MenuItem settingsMenuItem = menu.findItem(R.id.action_settings);
|
||||
Updatable fragment = fragments.get(fragments.size() - 1);
|
||||
settingsMenuItem.setVisible(fragment instanceof ReportFragment);
|
||||
if (fragments.size() > 0) {
|
||||
Updatable fragment = fragments.get(fragments.size() - 1);
|
||||
settingsMenuItem.setVisible(fragment instanceof ReportFragment);
|
||||
} else {
|
||||
settingsMenuItem.setVisible(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.action_settings) {
|
||||
|
@ -229,13 +283,13 @@ public class MainActivity extends AppCompatActivity {
|
|||
try {
|
||||
startActivity(intent);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
Snackbar bar = Snackbar.make(binding.fragmentContainer, R.string.no_settings, Snackbar.LENGTH_LONG);
|
||||
Snackbar bar = Snackbar.make(binding.viewpager, R.string.no_settings, Snackbar.LENGTH_LONG);
|
||||
bar.show();
|
||||
}
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_filter_options) {
|
||||
View menuItemView = findViewById(R.id.action_filter_options);
|
||||
PopupMenu popup = new PopupMenu(binding.fragmentContainer.getContext(), menuItemView);
|
||||
PopupMenu popup = new PopupMenu(binding.viewpager.getContext(), menuItemView);
|
||||
popup.getMenuInflater()
|
||||
.inflate(R.menu.popup_menu_filter, popup.getMenu());
|
||||
MenuItem filterByNameMI = popup.getMenu().findItem(R.id.filter_by_name);
|
||||
|
@ -282,4 +336,30 @@ public class MainActivity extends AppCompatActivity {
|
|||
return false;
|
||||
}
|
||||
|
||||
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
ScreenSlidePagerAdapter(FragmentManager fm) {
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(final int position) {
|
||||
//noinspection SwitchStatementWithTooFewBranches
|
||||
switch (position) {
|
||||
case 1:
|
||||
MyTrackersFragment myTrackersFragment = new MyTrackersFragment();
|
||||
myTrackersFragment.setOnTrackerClickListener(onTrackerClickListener);
|
||||
return myTrackersFragment;
|
||||
default:
|
||||
return home;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class Utils {
|
|||
public static final String LAST_REFRESH = "last_refresh";
|
||||
|
||||
public static String getDomain() {
|
||||
return BuildConfig.FLAVOR.compareTo("exodus") == 0 ? "reports.exodus-privacy.eu.org" : "exodus.phm.education.gouv.fr";
|
||||
return BuildConfig.amal ? "exodus.phm.education.gouv.fr" : "reports.exodus-privacy.eu.org";
|
||||
}
|
||||
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||
/*
|
||||
* Copyright (C) 2020 Thomas Schneider
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.databinding.MyTrackerItemBinding;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.MyTracker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class MyTrackersListAdapter extends RecyclerView.Adapter<MyTrackersListAdapter.TrackerListViewHolder> {
|
||||
|
||||
private final TrackerClickListener trackerClickListener;
|
||||
private final List<MyTracker> myTrackers;
|
||||
private final int max, installedApps;
|
||||
private int viewWidth = 0;
|
||||
|
||||
public MyTrackersListAdapter(List<MyTracker> mTrackers, TrackerClickListener listener, int maxValue, int appInstalled) {
|
||||
myTrackers = mTrackers;
|
||||
trackerClickListener = listener;
|
||||
max = maxValue;
|
||||
installedApps = appInstalled;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MyTrackersListAdapter.TrackerListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
MyTrackerItemBinding itemBinding = MyTrackerItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new TrackerListViewHolder(itemBinding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull MyTrackersListAdapter.TrackerListViewHolder holder, int position) {
|
||||
|
||||
if (myTrackers != null) {
|
||||
MyTracker myTracker = myTrackers.get(position);
|
||||
holder.viewDataBinding.trackerName.setText(myTracker.tracker.name);
|
||||
holder.viewDataBinding.trackerCount.setText(holder.viewDataBinding.trackerCount.getContext().getString(R.string.apps, String.valueOf(myTracker.number)));
|
||||
holder.viewDataBinding.getRoot().setOnClickListener(v -> trackerClickListener.onTrackerClick(myTracker.tracker.id));
|
||||
float percent = (float) myTracker.number / (float) max;
|
||||
int percentApp = myTracker.number * 100 / installedApps;
|
||||
holder.viewDataBinding.percent.getLayoutParams().width = (int) (viewWidth * percent);
|
||||
holder.viewDataBinding.percentVal.setText(String.format("%s %%", percentApp));
|
||||
if (percentApp >= 50)
|
||||
holder.viewDataBinding.trackerCount.setBackgroundResource(R.drawable.square_red);
|
||||
else if (percentApp >= 33)
|
||||
holder.viewDataBinding.trackerCount.setBackgroundResource(R.drawable.square_dark_orange);
|
||||
else if (percentApp >= 20)
|
||||
holder.viewDataBinding.trackerCount.setBackgroundResource(R.drawable.square_yellow);
|
||||
else
|
||||
holder.viewDataBinding.trackerCount.setBackgroundResource(R.drawable.square_light_blue);
|
||||
holder.viewDataBinding.percent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
holder.viewDataBinding.percent.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
if (viewWidth == 0) {
|
||||
viewWidth = holder.viewDataBinding.percent.getWidth();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else
|
||||
holder.viewDataBinding.trackerName.setText(R.string.no_trackers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return myTrackers.size();
|
||||
}
|
||||
|
||||
public interface TrackerClickListener {
|
||||
void onTrackerClick(long trackerId);
|
||||
}
|
||||
|
||||
static class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
MyTrackerItemBinding viewDataBinding;
|
||||
|
||||
TrackerListViewHolder(MyTrackerItemBinding dataBinding) {
|
||||
super(dataBinding.getRoot());
|
||||
viewDataBinding = dataBinding;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationListAdapter;
|
||||
|
@ -22,7 +21,7 @@ import java.util.List;
|
|||
|
||||
public class AppListFragment extends Fragment {
|
||||
|
||||
private static int firstVisiblePosition = 0;
|
||||
|
||||
private ApplistBinding applistBinding;
|
||||
private List<ApplicationViewModel> applications;
|
||||
private ApplicationListAdapter adapter;
|
||||
|
@ -43,18 +42,6 @@ public class AppListFragment extends Fragment {
|
|||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
|
||||
applistBinding.appList.setLayoutManager(linearLayoutManager);
|
||||
applistBinding.appList.setVerticalScrollBarEnabled(scrollbarEnabled);
|
||||
applistBinding.appList.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
||||
super.onScrollStateChanged(recyclerView, newState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
firstVisiblePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
|
||||
}
|
||||
});
|
||||
adapter = new ApplicationListAdapter(onAppClickListener);
|
||||
adapter.displayAppList(applications);
|
||||
adapter.filter(filterType, filterObject);
|
||||
|
@ -105,9 +92,6 @@ public class AppListFragment extends Fragment {
|
|||
return adapter.getDisplayedApps();
|
||||
}
|
||||
|
||||
public void scrollTo() {
|
||||
applistBinding.appList.scrollToPosition(firstVisiblePosition);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
NAME,
|
||||
|
|
|
@ -16,7 +16,7 @@ import java.util.Map;
|
|||
public class ComputeAppList {
|
||||
|
||||
private static final String gStore = "com.android.vending";
|
||||
private static final String fdroid = "ord.fdroid.fdroid";
|
||||
private static final String fdroid = "org.fdroid.fdroid";
|
||||
|
||||
|
||||
public static List<ApplicationViewModel> compute(PackageManager packageManager,
|
||||
|
@ -32,7 +32,7 @@ public class ComputeAppList {
|
|||
if (userOrderChoice == null) {
|
||||
userOrderChoice = order.DEFAULT;
|
||||
}
|
||||
vms = order(vms, userOrderChoice);
|
||||
order(vms, userOrderChoice);
|
||||
return vms;
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,8 @@ public class ComputeAppList {
|
|||
*
|
||||
* @param vms List<ApplicationViewModel>
|
||||
* @param orderChoice order
|
||||
* @return List<ApplicationViewModel>
|
||||
*/
|
||||
private static List<ApplicationViewModel> order(List<ApplicationViewModel> vms, order orderChoice) {
|
||||
private static void order(List<ApplicationViewModel> vms, order orderChoice) {
|
||||
if (orderChoice == order.LESS_TRACKERS) {
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.requestedPermissions != null ? obj1.requestedPermissions.length : 0, obj2.requestedPermissions != null ? obj2.requestedPermissions.length : 0));
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.trackers != null ? obj1.trackers.size() : 0, obj2.trackers != null ? obj2.trackers.size() : 0));
|
||||
|
@ -59,7 +58,6 @@ public class ComputeAppList {
|
|||
} else {
|
||||
Collections.sort(vms, (obj1, obj2) -> String.valueOf(obj1.label).compareToIgnoreCase(String.valueOf(obj2.label)));
|
||||
}
|
||||
return vms;
|
||||
}
|
||||
|
||||
private static void convertPackagesToViewModels(List<ApplicationViewModel> appsToBuild,
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ComputeAppListTask extends AsyncTask<Void, Void, List<ApplicationViewModel>> {
|
||||
|
||||
private static final String gStore = "com.android.vending";
|
||||
private static final String fdroid = "ord.fdroid.fdroid";
|
||||
private final WeakReference<PackageManager> packageManagerRef;
|
||||
private final WeakReference<DatabaseManager> databaseManagerRef;
|
||||
private final WeakReference<Listener> listenerRef;
|
||||
|
||||
order userOrderChoice;
|
||||
|
||||
ComputeAppListTask(WeakReference<PackageManager> packageManagerRef,
|
||||
WeakReference<DatabaseManager> databaseManagerRef,
|
||||
WeakReference<Listener> listenerRef, order orderChoice) {
|
||||
this.packageManagerRef = packageManagerRef;
|
||||
this.databaseManagerRef = databaseManagerRef;
|
||||
this.listenerRef = listenerRef;
|
||||
userOrderChoice = orderChoice;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
//Reordering should done here
|
||||
if (userOrderChoice == null) {
|
||||
userOrderChoice = order.DEFAULT;
|
||||
}
|
||||
vms = order(vms, userOrderChoice);
|
||||
return vms;
|
||||
}
|
||||
|
||||
private List<ApplicationViewModel> order(List<ApplicationViewModel> vms, order orderChoice) {
|
||||
if (orderChoice == order.LESS_TRACKERS) {
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.requestedPermissions != null ? obj1.requestedPermissions.length : 0, obj2.requestedPermissions != null ? obj2.requestedPermissions.length : 0));
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.trackers != null ? obj1.trackers.size() : 0, obj2.trackers != null ? obj2.trackers.size() : 0));
|
||||
} else if (orderChoice == order.MOST_TRACKERS) {
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj2.requestedPermissions != null ? obj2.requestedPermissions.length : 0, obj1.requestedPermissions != null ? obj1.requestedPermissions.length : 0));
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj2.trackers != null ? obj2.trackers.size() : 0, obj1.trackers != null ? obj1.trackers.size() : 0));
|
||||
} else if (orderChoice == order.LESS_PERMISSIONS) {
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.trackers != null ? obj1.trackers.size() : 0, obj2.trackers != null ? obj2.trackers.size() : 0));
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj1.requestedPermissions != null ? obj1.requestedPermissions.length : 0, obj2.requestedPermissions != null ? obj2.requestedPermissions.length : 0));
|
||||
} else if (orderChoice == order.MOST_PERMISSIONS) {
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj2.trackers != null ? obj2.trackers.size() : 0, obj1.trackers != null ? obj1.trackers.size() : 0));
|
||||
Collections.sort(vms, (obj1, obj2) -> Integer.compare(obj2.requestedPermissions != null ? obj2.requestedPermissions.length : 0, obj1.requestedPermissions != null ? obj1.requestedPermissions.length : 0));
|
||||
} else {
|
||||
Collections.sort(vms, (obj1, obj2) -> String.valueOf(obj1.label).compareToIgnoreCase(String.valueOf(obj2.label)));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public enum order {
|
||||
DEFAULT,
|
||||
MOST_TRACKERS,
|
||||
LESS_TRACKERS,
|
||||
MOST_PERMISSIONS,
|
||||
LESS_PERMISSIONS,
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
void onAppsComputed(List<ApplicationViewModel> apps);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
|
@ -71,7 +72,7 @@ public class HomeFragment extends Fragment implements ComputeAppList.Listener, U
|
|||
packageManager = context.getPackageManager();
|
||||
homeBinding.swipeRefresh.setOnRefreshListener(this::startRefresh);
|
||||
|
||||
SharedPreferences sharedPreferences = getContext().getSharedPreferences(Utils.APP_PREFS, MODE_PRIVATE);
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(Utils.APP_PREFS, MODE_PRIVATE);
|
||||
last_refresh = sharedPreferences.getString(Utils.LAST_REFRESH, null);
|
||||
|
||||
if (packageManager != null) {
|
||||
|
@ -94,12 +95,13 @@ public class HomeFragment extends Fragment implements ComputeAppList.Listener, U
|
|||
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);
|
||||
@SuppressLint("QueryPermissionsNeeded") List<PackageInfo> packageInstalled = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
ArrayList<String> packageList = new ArrayList<>();
|
||||
for (PackageInfo pkgInfo : packageInstalled)
|
||||
packageList.add(pkgInfo.packageName);
|
||||
|
@ -114,7 +116,9 @@ public class HomeFragment extends Fragment implements ComputeAppList.Listener, U
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
appListFragment.scrollTo();
|
||||
if (!refreshInProgress && homeBinding.layoutProgress.getVisibility() == View.VISIBLE) {
|
||||
onUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||
/*
|
||||
* Copyright (C) 2020 Thomas Schneider
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.MyTrackersListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.databinding.MyTrackersBinding;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.MyTracker;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Tracker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class MyTrackersFragment extends Fragment implements MyTrackersListAdapter.TrackerClickListener {
|
||||
|
||||
private Context context;
|
||||
private MyTrackersBinding trackerBinding;
|
||||
private TrackerListAdapter.OnTrackerClickListener onTrackerClickListener;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
context = getContext();
|
||||
trackerBinding = MyTrackersBinding.inflate(LayoutInflater.from(context));
|
||||
return trackerBinding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
|
||||
trackerBinding.loader.setVisibility(View.VISIBLE);
|
||||
trackerBinding.trackers.setVisibility(View.GONE);
|
||||
trackerBinding.swipeRefresh.setOnRefreshListener(this::refresh);
|
||||
trackerBinding.refresh.setOnClickListener(v -> refresh());
|
||||
refresh();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void refresh() {
|
||||
new Thread(() -> {
|
||||
DatabaseManager databaseManager = DatabaseManager.getInstance(getActivity());
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> packageInstalled = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
|
||||
List<MyTracker> myTrackers = new ArrayList<>();
|
||||
List<String> added = new ArrayList<>();
|
||||
int maxValue = 0;
|
||||
|
||||
List<ApplicationViewModel> vms = ComputeAppList.compute(packageManager, DatabaseManager.getInstance(getActivity()), null);
|
||||
int appInstalled = vms.size();
|
||||
for (PackageInfo pkgInfo : packageInstalled) {
|
||||
Report report;
|
||||
if (pkgInfo.versionName != null)
|
||||
report = databaseManager.getReportFor(pkgInfo.packageName, pkgInfo.versionName, null);
|
||||
else {
|
||||
report = databaseManager.getReportFor(pkgInfo.packageName, pkgInfo.versionCode, null);
|
||||
}
|
||||
if (report != null) {
|
||||
Set<Tracker> trackersApp = databaseManager.getTrackers(report.trackers);
|
||||
for (Tracker tracker : trackersApp) {
|
||||
if (added.contains(tracker.codeSignature)) {
|
||||
for (MyTracker myTracker : myTrackers) {
|
||||
if (myTracker.signature.compareTo(tracker.codeSignature) == 0) {
|
||||
myTracker.number += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MyTracker myTracker = new MyTracker();
|
||||
myTracker.signature = tracker.codeSignature;
|
||||
myTracker.number = 1;
|
||||
myTracker.tracker = tracker;
|
||||
myTrackers.add(myTracker);
|
||||
added.add(myTracker.signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MyTracker myTracker : myTrackers) {
|
||||
if (myTracker.number > maxValue)
|
||||
maxValue = myTracker.number;
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
int finalMaxValue = maxValue;
|
||||
Runnable myRunnable = () -> {
|
||||
if (myTrackers.size() > 0) {
|
||||
Collections.sort(myTrackers, (obj1, obj2) -> Integer.compare(obj2.number, obj1.number));
|
||||
MyTrackersListAdapter myTrackersListAdapter = new MyTrackersListAdapter(myTrackers, MyTrackersFragment.this, finalMaxValue, appInstalled);
|
||||
trackerBinding.trackers.setAdapter(myTrackersListAdapter);
|
||||
trackerBinding.trackers.setLayoutManager(new LinearLayoutManager(context));
|
||||
trackerBinding.trackers.setVisibility(View.VISIBLE);
|
||||
trackerBinding.loader.setVisibility(View.GONE);
|
||||
trackerBinding.refresh.setVisibility(View.GONE);
|
||||
} else {
|
||||
trackerBinding.refresh.setVisibility(View.VISIBLE);
|
||||
trackerBinding.trackers.setVisibility(View.GONE);
|
||||
trackerBinding.loader.setVisibility(View.GONE);
|
||||
}
|
||||
trackerBinding.swipeRefresh.setRefreshing(false);
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.action_filter).setVisible(false);
|
||||
menu.findItem(R.id.action_settings).setVisible(false);
|
||||
menu.findItem(R.id.action_filter_options).setVisible(false);
|
||||
}
|
||||
|
||||
public void setOnTrackerClickListener(TrackerListAdapter.OnTrackerClickListener listener) {
|
||||
onTrackerClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackerClick(long trackerId) {
|
||||
onTrackerClickListener.onTrackerClick(trackerId);
|
||||
}
|
||||
}
|
|
@ -166,6 +166,7 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.action_filter).setVisible(false);
|
||||
menu.findItem(R.id.action_filter_options).setVisible(false);
|
||||
menu.findItem(R.id.action_settings).setVisible(true);
|
||||
}
|
||||
|
||||
public ApplicationViewModel getModel() {
|
||||
|
|
|
@ -221,11 +221,18 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
if (cursor.moveToFirst()) {
|
||||
long appId = cursor.getLong(0);
|
||||
cursor.close();
|
||||
where = "app_id = ? and version = ? and source = ?";
|
||||
whereArgs = new String[3];
|
||||
whereArgs[0] = String.valueOf(appId);
|
||||
whereArgs[1] = version;
|
||||
whereArgs[2] = source;
|
||||
if (source != null) {
|
||||
where = "app_id = ? and version = ? and source = ?";
|
||||
whereArgs = new String[3];
|
||||
whereArgs[0] = String.valueOf(appId);
|
||||
whereArgs[1] = version;
|
||||
whereArgs[2] = source;
|
||||
} else {
|
||||
where = "app_id = ? and version = ?";
|
||||
whereArgs = new String[2];
|
||||
whereArgs[0] = String.valueOf(appId);
|
||||
whereArgs[1] = version;
|
||||
}
|
||||
String order = "id ASC";
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
long reportId;
|
||||
|
@ -234,13 +241,20 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
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;
|
||||
if (source != null) {
|
||||
where = "app_id = ? and source = ?";
|
||||
whereArgs = new String[2];
|
||||
whereArgs[0] = String.valueOf(appId);
|
||||
whereArgs[1] = source;
|
||||
} else {
|
||||
where = "app_id = ?";
|
||||
whereArgs = new String[1];
|
||||
whereArgs[0] = String.valueOf(appId);
|
||||
}
|
||||
order = "creation DESC";
|
||||
//search a recent reports
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
|
|
|
@ -246,7 +246,6 @@ public class NetworkManager {
|
|||
}
|
||||
|
||||
|
||||
|
||||
private void getApplications(Message mes) {
|
||||
mes.listener.onProgress(R.string.get_reports_connection, 0, 0);
|
||||
URL url;
|
||||
|
@ -354,8 +353,8 @@ public class NetworkManager {
|
|||
JSONObject object = makeDataRequest(mes.context, mes.listener, url);
|
||||
if (object != null) {
|
||||
try {
|
||||
JSONObject application = object.getJSONObject(handle);
|
||||
if (handle != null) {
|
||||
JSONObject application = object.getJSONObject(handle);
|
||||
return parseApplication(application, handle);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
@ -401,7 +400,7 @@ public class NetworkManager {
|
|||
|
||||
report.creationDate = Calendar.getInstance();
|
||||
report.creationDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
report.creationDate.setTime(date);
|
||||
report.creationDate.setTime(date!=null?date:new Date());
|
||||
date = dateFormat.parse(object.getString("creation_date"));
|
||||
if (date != null) {
|
||||
report.creationDate.setTime(date);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||
|
||||
public class MyTracker {
|
||||
|
||||
public String signature;
|
||||
public Tracker tracker;
|
||||
public int number;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM9,17L7,17v-5h2v5zM13,17h-2v-3h2v3zM13,12h-2v-2h2v2zM17,17h-2L15,7h2v10z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="64dp"
|
||||
android:height="64dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z" />
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/percent" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/colorPrimary" />
|
||||
<corners android:radius="5dp" />
|
||||
<padding
|
||||
android:bottom="0dp"
|
||||
android:left="0dp"
|
||||
android:right="0dp"
|
||||
android:top="0dp" />
|
||||
</shape>
|
|
@ -1,20 +1,73 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<layout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<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/>
|
||||
<FrameLayout
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:id="@+id/fragment_container"
|
||||
tools:context="org.eu.exodus_privacy.exodusprivacy.MainActivity">
|
||||
|
||||
<data />
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?colorPrimary"
|
||||
android:fitsSystemWindows="true"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark"
|
||||
app:layout_scrollFlags="scroll|enterAlways"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="?attr/actionBarSize"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="?attr/actionBarSize"
|
||||
android:visibility="gone"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:background="?android:attr/windowBackground" />
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
</layout>
|
|
@ -0,0 +1,71 @@
|
|||
<?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 />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<View
|
||||
android:id="@+id/percent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/percent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/percent_val"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/percent"
|
||||
app:layout_constraintStart_toStartOf="@+id/percent"
|
||||
app:layout_constraintTop_toTopOf="@+id/percent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracker_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/textColorDark"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tracker_count"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/percent" />
|
||||
|
||||
<TextView
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:id="@+id/tracker_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:textColor="@color/textColorWhite"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/tracker_name"
|
||||
app:layout_constraintTop_toTopOf="@id/tracker_name" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/details"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_baseline_navigate_next_24"
|
||||
android:contentDescription="@string/list_of_apps" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
|
@ -0,0 +1,51 @@
|
|||
<?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">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/refresh"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/nothing_here"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipe_refresh"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/trackers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
|
@ -11,6 +11,7 @@
|
|||
type="org.eu.exodus_privacy.exodusprivacy.ReportViewModel" />
|
||||
</data>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<data>
|
||||
</data>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_apps"
|
||||
android:icon="@drawable/ic_baseline_apps_24"
|
||||
android:title="@string/title_apps" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_analytics"
|
||||
android:icon="@drawable/ic_baseline_analytics_24"
|
||||
android:title="@string/title_trackers" />
|
||||
|
||||
</menu>
|
|
@ -62,6 +62,11 @@
|
|||
<string name="submit">Submit</string>
|
||||
<string name="app_not_analyzed">Would you like to analyze the app?\n\nThe app id will be automatically pasted to the website form. You will only need to submit the form.</string>
|
||||
<string name="app_not_analyzed_title">This app has not been analyzed!</string>
|
||||
<string name="title_apps">My apps</string>
|
||||
<string name="title_trackers">Trackers</string>
|
||||
<string name="list_of_apps">See the list of apps</string>
|
||||
<string name="apps">%1$s apps</string>
|
||||
<string name="nothing_here">Nothing to display currently. You can pull to refresh!</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
|
|