Compare commits
45 Commits
c02568e621
...
64a2e223b3
Author | SHA1 | Date |
---|---|---|
Thomas | 64a2e223b3 | |
Thomas | 90848c678a | |
Thomas | 6b5631bb43 | |
Thomas | 2f531d7d24 | |
Thomas | e3f2325d00 | |
Thomas | 3d5b4fd04f | |
Thomas | 3d1320eeb9 | |
Thomas | 7d4d2533ac | |
Thomas | c40afdf348 | |
Thomas | ae020fe1cc | |
Thomas | 20f2e8412f | |
Thomas | 9d330bf07f | |
Thomas | cae158d489 | |
Thomas | efe9a88209 | |
Thomas | 3bf596f1cf | |
Thomas | 7e6e1fcff6 | |
Thomas | 2a091043c6 | |
Thomas | e64e04398a | |
Thomas | e4b8dc9ad7 | |
Thomas | 8e4db1d284 | |
Thomas | 55303f158e | |
Thomas | 91682ed3b1 | |
Thomas | a9e72c0cb3 | |
Thomas | 7952449247 | |
Thomas | 22e1cbb221 | |
Thomas | 501e0ae9f4 | |
Thomas | a247cc997e | |
Thomas | 53553940d3 | |
Thomas | acfc183eec | |
Thomas | 8209559012 | |
Thomas | 891198b71f | |
Thomas | 5ec97f3f81 | |
Thomas | 85097ce51b | |
Thomas | 80046985c0 | |
Thomas | 3b7343bc68 | |
Thomas | 883b623d6d | |
Thomas | 91f5dea591 | |
Thomas | 18c19ace49 | |
Thomas | 62467a3fe1 | |
Thomas | 555f108853 | |
stom79 | 5723d9ea8d | |
stom79 | d81078659a | |
stom79 | b2fde810cd | |
stom79 | 956e0ba963 | |
stom79 | 341d0dafe3 |
|
@ -1,6 +1,10 @@
|
|||
language: android
|
||||
java: oraclejdk8
|
||||
|
||||
before_install:
|
||||
- yes | sdkmanager "platforms;android-30"
|
||||
- yes | sdkmanager "build-tools;30.0.2"
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
@ -15,8 +19,8 @@ android:
|
|||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-29.0.3
|
||||
- android-29
|
||||
- build-tools-30.0.2
|
||||
- android-30
|
||||
- extra-m2-repository
|
||||
- sys-img-armeabi-v7a-android-28
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.2"
|
||||
defaultConfig {
|
||||
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode 10
|
||||
versionName "2.1.1"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
flavorDimensions "default"
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
|
@ -20,6 +20,67 @@ android {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
checkReleaseBuilds false
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
exodus_google {
|
||||
applicationId "org.eu.exodus_privacy.exodusprivacy"
|
||||
buildConfigField "boolean", "amal", "false"
|
||||
}
|
||||
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_google {
|
||||
res.srcDirs = ['src/main/res', 'src/exodus/res']
|
||||
manifest.srcFile 'src/google/AndroidManifest.xml'
|
||||
}
|
||||
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'
|
||||
}
|
||||
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
@ -31,13 +92,13 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 20 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="0.24190092"
|
||||
android:scaleY="0.24190092"
|
||||
android:translateX="25.122473"
|
||||
android:translateY="22.68">
|
||||
<path
|
||||
android:fillColor="#007ea5"
|
||||
android:pathData="M59.689,30.169l59.032,-30.169l120.034,59.455l-61.001,29.469l-118.065,-58.755z" />
|
||||
<path
|
||||
android:fillColor="#00bedd"
|
||||
android:pathData="M177.754,154.21l0,-65.286l-59.033,-29.469l0,60.162l59.033,34.593z" />
|
||||
<path
|
||||
android:fillColor="#03cfe5"
|
||||
android:pathData="M118.721,189.589l59.033,-35.379l-59.033,-34.593l-59.032,34.593l59.032,35.379z" />
|
||||
<path
|
||||
android:fillColor="#0099bc"
|
||||
android:pathData="M59.689,88.924l59.032,-29.469l0,60.162l-59.032,34.593l0,-65.286z" />
|
||||
<path
|
||||
android:fillColor="#005e8b"
|
||||
android:pathData="M0,119.617l0,69.972l118.721,69.36l120.034,-69.36l0,-130.134l-61.001,29.469l0,65.286l-59.033,35.379l-59.032,-35.379l0,-65.286l-59.689,30.693z" />
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="238.755dp"
|
||||
android:height="258.949dp"
|
||||
android:viewportWidth="238.755"
|
||||
android:viewportHeight="258.949">
|
||||
<path
|
||||
android:fillColor="#007ea5"
|
||||
android:pathData="M59.689,30.169l59.032,-30.169l120.034,59.455l-61.001,29.469l-118.065,-58.755z" />
|
||||
<path
|
||||
android:fillColor="#00bedd"
|
||||
android:pathData="M177.754,154.21l0,-65.286l-59.033,-29.469l0,60.162l59.033,34.593z" />
|
||||
<path
|
||||
android:fillColor="#03cfe5"
|
||||
android:pathData="M118.721,189.589l59.033,-35.379l-59.033,-34.593l-59.032,34.593l59.032,35.379z" />
|
||||
<path
|
||||
android:fillColor="#0099bc"
|
||||
android:pathData="M59.689,88.924l59.032,-29.469l0,60.162l-59.032,34.593l0,-65.286z" />
|
||||
<path
|
||||
android:fillColor="#005e8b"
|
||||
android:pathData="M0,119.617l0,69.972l118.721,69.36l120.034,-69.36l0,-130.134l-61.001,29.469l0,65.286l-59.033,35.379l-59.032,-35.379l0,-65.286l-59.689,30.693z" />
|
||||
</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: 2.1 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#005e8b</color>
|
||||
<color name="colorPrimaryDark">#005e8b</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>
|
||||
|
||||
<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">16f8c1a973ecb6622a606daaef35736dc3521e30</string>
|
||||
<string name="app_title">AMAL</string>
|
||||
<string name="app_name">AMAL</string>
|
||||
</resources>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
After Width: | Height: | Size: 18 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="#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: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>
|
|
@ -1,10 +1,21 @@
|
|||
<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"
|
||||
<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="#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: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:strokeAlpha="1" android:strokeColor="#00000000"
|
||||
android:strokeLineCap="butt" android:strokeLineJoin="miter" android:strokeWidth="0.03275258"/>
|
||||
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.8 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -2,7 +2,8 @@
|
|||
<resources>
|
||||
<color name="colorPrimary">#684971</color>
|
||||
<color name="colorPrimaryDark">#3d2b43</color>
|
||||
<color name="colorAccent">#684971</color>
|
||||
<color name="colorAccent">#3d2b43</color>
|
||||
<color name="percent">#77684971</color>
|
||||
|
||||
<color name="colorGreen">#6fc384</color>
|
||||
<color name="colorLightRed">#e46772</color>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#684971</color>
|
||||
</resources>
|
|
@ -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>
|
|
@ -1,9 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="54"
|
||||
android:viewportWidth="54">
|
||||
android:width="100dp"
|
||||
android:height="100dp"
|
||||
android:viewportWidth="54"
|
||||
android:viewportHeight="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" />
|
||||
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"
|
||||
|
@ -13,16 +15,31 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
android:largeHeap="true"
|
||||
>
|
||||
<activity android:name=".MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
>
|
||||
android:largeHeap="true">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".CheckAppActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.Popup">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:host="play.google.com" />
|
||||
<data android:host="f-droid.org" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy;
|
||||
/*
|
||||
* 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.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.databinding.AppCheckActivityBinding;
|
||||
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.manager.DatabaseManager;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.NetworkManager;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Report;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.ReportDisplay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CheckAppActivity extends AppCompatActivity implements NetworkListener, TrackerListAdapter.OnTrackerClickListener {
|
||||
|
||||
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.-]+)");
|
||||
ArrayList<Updatable> fragments;
|
||||
AppCheckActivityBinding binding;
|
||||
TrackerListAdapter.OnTrackerClickListener onTrackerClickListener = id -> {
|
||||
TrackerFragment tracker = TrackerFragment.newInstance(id);
|
||||
fragments.add(tracker);
|
||||
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, tracker)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
};
|
||||
private String app_id;
|
||||
private TrackerListAdapter.OnTrackerClickListener trackerClickListener;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = getIntent();
|
||||
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
|
||||
if (extraText != null) {
|
||||
Matcher matcher = fdroidRegex.matcher(extraText);
|
||||
app_id = null;
|
||||
while (matcher.find()) {
|
||||
app_id = matcher.group(2);
|
||||
}
|
||||
if (app_id == null) {
|
||||
matcher = googleRegex.matcher(extraText);
|
||||
while (matcher.find()) {
|
||||
app_id = matcher.group(1);
|
||||
}
|
||||
}
|
||||
setOnTrackerClickListener(trackerClickListener);
|
||||
fragments = new ArrayList<>();
|
||||
NetworkManager.getInstance().getSingleReport(CheckAppActivity.this, this, app_id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void setOnTrackerClickListener(TrackerListAdapter.OnTrackerClickListener listener) {
|
||||
trackerClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Application application) {
|
||||
|
||||
runOnUiThread(() -> {
|
||||
|
||||
|
||||
if (application == null) {
|
||||
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.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);
|
||||
}
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(browserIntent);
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
});
|
||||
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
});
|
||||
dialogBuilder.setOnDismissListener(dialogInterface -> finish());
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationViewModel applicationViewModel = new ApplicationViewModel();
|
||||
|
||||
applicationViewModel.packageName = application.packageName;
|
||||
applicationViewModel.label = application.name;
|
||||
|
||||
Report reportToKeep = null;
|
||||
long versionCode = -1;
|
||||
for (Report report : application.reports) {
|
||||
if (versionCode == -1) {
|
||||
reportToKeep = report;
|
||||
versionCode = report.versionCode;
|
||||
} else if (report.versionCode > versionCode) {
|
||||
reportToKeep = report;
|
||||
versionCode = report.versionCode;
|
||||
}
|
||||
}
|
||||
applicationViewModel.report = reportToKeep;
|
||||
applicationViewModel.source = reportToKeep.source;
|
||||
applicationViewModel.versionCode = (int) reportToKeep.versionCode;
|
||||
applicationViewModel.versionName = reportToKeep.version;
|
||||
applicationViewModel.trackers = DatabaseManager.getInstance(CheckAppActivity.this).getTrackers(reportToKeep.trackers);
|
||||
ReportDisplay reportDisplay = ReportDisplay.buildReportDisplay(CheckAppActivity.this, applicationViewModel, null, null);
|
||||
ReportViewModel viewModel = new ReportViewModel();
|
||||
|
||||
viewModel.setReportDisplay(reportDisplay);
|
||||
TrackerListAdapter trackerAdapter = new TrackerListAdapter(reportDisplay.trackers, R.layout.tracker_item, onTrackerClickListener);
|
||||
|
||||
binding = AppCheckActivityBinding.inflate(getLayoutInflater());
|
||||
binding.reportUrl.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse("https://" + Utils.getDomain() + "/reports/" + reportDisplay.report.id + "/"));
|
||||
startActivity(intent);
|
||||
});
|
||||
binding.setReportInfo(viewModel);
|
||||
binding.trackers.setAdapter(trackerAdapter);
|
||||
binding.trackers.setLayoutManager(new LinearLayoutManager(CheckAppActivity.this));
|
||||
View viewRoot = binding.getRoot();
|
||||
setContentView(viewRoot);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(int resourceId, int progress, int maxProgress) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackerClick(long trackerId) {
|
||||
|
||||
}
|
||||
}
|
|
@ -18,70 +18,96 @@
|
|||
|
||||
package org.eu.exodus_privacy.exodusprivacy;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.SearchView;
|
||||
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;
|
||||
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.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;
|
||||
import org.eu.exodus_privacy.exodusprivacy.listener.NetworkListener;
|
||||
import org.eu.exodus_privacy.exodusprivacy.manager.DatabaseManager;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static ComputeAppList.order order = ComputeAppList.order.DEFAULT;
|
||||
private List<Updatable> fragments;
|
||||
private SearchView searchView;
|
||||
private Menu toolbarMenu;
|
||||
private MenuItem settingsMenuItem;
|
||||
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) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = DataBindingUtil.setContentView(this,R.layout.main);
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.main);
|
||||
final MainBinding mainBinding = binding;
|
||||
getSupportActionBar().setTitle(R.string.app_title);
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setTitle(R.string.app_title);
|
||||
}
|
||||
fragments = new ArrayList<>();
|
||||
|
||||
NetworkListener networkListener = new NetworkListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
public void onSuccess(Application application) {
|
||||
runOnUiThread(() -> {
|
||||
for(Updatable updatable : fragments){
|
||||
if(updatable instanceof ReportFragment) {
|
||||
for (Updatable updatable : fragments) {
|
||||
if (updatable instanceof ReportFragment) {
|
||||
ApplicationViewModel model = ((ReportFragment) updatable).getModel();
|
||||
if(model.versionName == null)
|
||||
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.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();
|
||||
|
@ -92,10 +118,10 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onError(String error) {
|
||||
runOnUiThread(() -> {
|
||||
for(Updatable updatable : fragments){
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
@ -106,55 +132,86 @@ 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)
|
||||
.replace(R.id.fragment_container, tracker)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
};
|
||||
|
||||
onAppClickListener = vm -> {
|
||||
|
||||
onAppClickListener = (vm) -> {
|
||||
try {
|
||||
|
||||
PackageManager pm = getPackageManager();
|
||||
PackageInfo packageInfo = pm.getPackageInfo(vm.packageName, PackageManager.GET_PERMISSIONS);
|
||||
|
||||
ReportFragment report = ReportFragment.newInstance(pm,vm,packageInfo,onTrackerClickListener);
|
||||
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)
|
||||
.replace(R.id.fragment_container, report)
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
|
||||
binding.fragmentContainer.setVisibility(View.VISIBLE);
|
||||
packageName = packageInfo.packageName;
|
||||
|
||||
searchView.clearFocus();
|
||||
if (toolbarMenu != null)
|
||||
(toolbarMenu.findItem(R.id.action_filter)).collapseActionView();
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -164,56 +221,145 @@ public class MainActivity extends AppCompatActivity {
|
|||
finish();
|
||||
else {
|
||||
getSupportFragmentManager().popBackStack();
|
||||
fragments.remove(fragments.size()-1);
|
||||
fragments.remove(fragments.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
toolbarMenu = menu;
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.main, menu);
|
||||
searchView = (SearchView) menu.findItem(R.id.action_filter).getActionView();
|
||||
searchView.setIconifiedByDefault(false);
|
||||
MenuItem actionFilterItem = menu.findItem(R.id.action_filter);
|
||||
|
||||
searchView = (SearchView) actionFilterItem.getActionView();
|
||||
searchView.setOnQueryTextFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
searchView.setQuery(previousQuery, false);
|
||||
}
|
||||
});
|
||||
ImageView searchClose = searchView.findViewById(androidx.appcompat.R.id.search_close_btn);
|
||||
if (searchClose != null) {
|
||||
searchClose.setOnClickListener(v -> {
|
||||
previousQuery = "";
|
||||
searchView.setQuery("", true);
|
||||
});
|
||||
}
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
previousQuery = query.trim();
|
||||
if (!searchView.isIconified()) {
|
||||
searchView.setIconified(true);
|
||||
}
|
||||
menu.findItem(R.id.action_filter).collapseActionView();
|
||||
HomeFragment home = (HomeFragment) fragments.get(0);
|
||||
home.filter(query);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
HomeFragment home = (HomeFragment) fragments.get(0);
|
||||
home.filter(newText);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
settingsMenuItem = menu.findItem(R.id.action_settings);
|
||||
Updatable fragment = fragments.get(fragments.size()-1);
|
||||
if (fragment instanceof ReportFragment)
|
||||
settingsMenuItem.setVisible(true);
|
||||
else
|
||||
MenuItem settingsMenuItem = menu.findItem(R.id.action_settings);
|
||||
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) {
|
||||
if (item.getItemId() == R.id.action_settings) {
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.fromParts("package",packageName,null));
|
||||
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);
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
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.viewpager.getContext(), menuItemView);
|
||||
popup.getMenuInflater()
|
||||
.inflate(R.menu.popup_menu_filter, popup.getMenu());
|
||||
MenuItem filterByNameMI = popup.getMenu().findItem(R.id.filter_by_name);
|
||||
MenuItem lessTrackersMI = popup.getMenu().findItem(R.id.having_less_trackers);
|
||||
MenuItem mostTrackersMI = popup.getMenu().findItem(R.id.having_most_trackers);
|
||||
MenuItem lessPermissionsMI = popup.getMenu().findItem(R.id.having_less_permissions);
|
||||
MenuItem mostPermissionsMI = popup.getMenu().findItem(R.id.having_most_permissions);
|
||||
switch (order) {
|
||||
case LESS_TRACKERS:
|
||||
lessTrackersMI.setChecked(true);
|
||||
break;
|
||||
case MOST_TRACKERS:
|
||||
mostTrackersMI.setChecked(true);
|
||||
break;
|
||||
case LESS_PERMISSIONS:
|
||||
lessPermissionsMI.setChecked(true);
|
||||
break;
|
||||
case MOST_PERMISSIONS:
|
||||
mostPermissionsMI.setChecked(true);
|
||||
break;
|
||||
default:
|
||||
filterByNameMI.setChecked(true);
|
||||
}
|
||||
popup.setOnMenuItemClickListener(filter_item -> {
|
||||
if (filter_item.getItemId() == R.id.filter_by_name) {
|
||||
order = ComputeAppList.order.DEFAULT;
|
||||
} else if (filter_item.getItemId() == R.id.having_less_trackers) {
|
||||
order = ComputeAppList.order.LESS_TRACKERS;
|
||||
} else if (filter_item.getItemId() == R.id.having_most_trackers) {
|
||||
order = ComputeAppList.order.MOST_TRACKERS;
|
||||
} else if (filter_item.getItemId() == R.id.having_most_permissions) {
|
||||
order = ComputeAppList.order.MOST_PERMISSIONS;
|
||||
} else if (filter_item.getItemId() == R.id.having_less_permissions) {
|
||||
order = ComputeAppList.order.LESS_PERMISSIONS;
|
||||
}
|
||||
if (fragments != null && fragments.size() > 0 && fragments.get(0) instanceof HomeFragment) {
|
||||
HomeFragment home = (HomeFragment) fragments.get(0);
|
||||
home.displayAppListAsync(order);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ 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;
|
||||
|
@ -17,7 +16,7 @@ import java.text.SimpleDateFormat;
|
|||
public class ReportViewModel extends BaseObservable {
|
||||
private ReportDisplay reportDisplay;
|
||||
|
||||
public void setReportDisplay(ReportDisplay report){
|
||||
public void setReportDisplay(ReportDisplay report) {
|
||||
this.reportDisplay = report;
|
||||
notifyChange();
|
||||
}
|
||||
|
@ -54,8 +53,8 @@ public class ReportViewModel extends BaseObservable {
|
|||
|
||||
@Bindable
|
||||
public boolean getHasPermissionDangerous() {
|
||||
for(Permission perm : reportDisplay.permissions) {
|
||||
if(perm.dangerous)
|
||||
for (Permission perm : reportDisplay.permissions) {
|
||||
if (perm.dangerous)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -85,7 +84,7 @@ public class ReportViewModel extends BaseObservable {
|
|||
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));
|
||||
download = download.replace("downloads", context.getString(R.string.downloads));
|
||||
creator += " (" + download + ")";
|
||||
}
|
||||
return creator;
|
||||
|
@ -103,7 +102,7 @@ public class ReportViewModel extends BaseObservable {
|
|||
|
||||
@Bindable
|
||||
public String getReportVersion() {
|
||||
if(reportDisplay.report != null) {
|
||||
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) {
|
||||
|
@ -125,30 +124,30 @@ public class ReportViewModel extends BaseObservable {
|
|||
|
||||
public String getReportDate(Context context) {
|
||||
String reportDate = "";
|
||||
if(reportDisplay.report == null)
|
||||
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())+".";
|
||||
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 "";
|
||||
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)
|
||||
if (reportDisplay.permissions != null && reportDisplay.permissions.size() > 0)
|
||||
return context.getString(R.string.code_permission_found);
|
||||
else if(reportDisplay.permissions != null)
|
||||
else if (reportDisplay.permissions != null)
|
||||
return context.getString(R.string.code_permission_not_found);
|
||||
else
|
||||
return "";
|
||||
|
@ -158,7 +157,7 @@ public class ReportViewModel extends BaseObservable {
|
|||
private int getColor(int number) {
|
||||
if (number == 0)
|
||||
return R.drawable.square_green;
|
||||
else if(number < 5)
|
||||
else if (number < 5)
|
||||
return R.drawable.square_light_yellow;
|
||||
else
|
||||
return R.drawable.square_light_red;
|
||||
|
@ -174,5 +173,4 @@ public class ReportViewModel extends BaseObservable {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
@ -12,12 +14,25 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Utils {
|
||||
|
||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||
public static final String TAG = "Exodus_privacy";
|
||||
|
||||
public static final String APP_PREFS = "app_prefs";
|
||||
public static final String LAST_REFRESH = "last_refresh";
|
||||
|
||||
public static String getDomain() {
|
||||
return BuildConfig.amal ? "exodus.phm.education.gouv.fr" : "reports.exodus-privacy.eu.org";
|
||||
}
|
||||
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
public static String getCertificateSHA1Fingerprint(PackageManager pm, String packageName) {
|
||||
int flags = PackageManager.GET_SIGNATURES;
|
||||
|
@ -34,7 +49,7 @@ public class Utils {
|
|||
builder.append(packageName);
|
||||
|
||||
|
||||
for(Signature signature: signatures) {
|
||||
for (Signature signature : signatures) {
|
||||
InputStream input = new ByteArrayInputStream(signature.toByteArray());
|
||||
CertificateFactory cf = null;
|
||||
try {
|
||||
|
@ -83,6 +98,47 @@ public class Utils {
|
|||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a date in String -> format yyyy-MM-dd HH:mm:ss
|
||||
*
|
||||
* @param date Date
|
||||
* @return String
|
||||
*/
|
||||
public static String dateToString(Date date) {
|
||||
if (date == null)
|
||||
return null;
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert String date from db to Date Object
|
||||
*
|
||||
* @param stringDate date to convert
|
||||
* @return Date
|
||||
*/
|
||||
public static Date stringToDate(Context context, String stringDate) {
|
||||
if (stringDate == null)
|
||||
return null;
|
||||
Locale userLocale;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
userLocale = context.getResources().getConfiguration().getLocales().get(0);
|
||||
} else {
|
||||
userLocale = context.getResources().getConfiguration().locale;
|
||||
}
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", userLocale);
|
||||
Date date = null;
|
||||
try {
|
||||
date = dateFormat.parse(stringDate);
|
||||
} catch (java.text.ParseException ignored) {
|
||||
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Simple and not complete markdownToHtml converter
|
||||
*/
|
||||
|
@ -92,18 +148,18 @@ public class Utils {
|
|||
ArrayList<String> listStarter = new ArrayList<>();
|
||||
ArrayList<String> formatStarter = new ArrayList<>();
|
||||
ArrayList<String> closeTags = new ArrayList<>();
|
||||
for(String line : lines) {
|
||||
for (String line : lines) {
|
||||
if (line.matches("^#{1,5} .*")) {
|
||||
int nb = line.indexOf(" ");
|
||||
String hx = "<h"+nb+">";
|
||||
String endhx = "</h"+nb+">";
|
||||
String hx = "<h" + nb + ">";
|
||||
String endhx = "</h" + nb + ">";
|
||||
builder.append(hx);
|
||||
closeTags.add(endhx);
|
||||
line = line.substring(line.indexOf(" ")+1);
|
||||
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);
|
||||
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);
|
||||
|
@ -115,19 +171,22 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
builder.append("<li> ");
|
||||
int beginIndex = line.indexOf(starter)+starter.length();
|
||||
int beginIndex = 0;
|
||||
if (starter != null) {
|
||||
beginIndex = line.indexOf(starter) + starter.length();
|
||||
}
|
||||
line = line.substring(beginIndex);
|
||||
closeTags.add("</li>");
|
||||
} else {
|
||||
while(!listStarter.isEmpty()) {
|
||||
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.+?)(?=\\))\\)");
|
||||
while (!line.isEmpty()) {
|
||||
Pattern pattern = Pattern.compile("^\\[(.+?)(?=]\\()]\\((http.+?)(?=\\))\\)");
|
||||
//Pattern pattern = Pattern.compile("^\\[(.*)\\]\\((http.*)\\)");
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.find()) {
|
||||
|
@ -136,7 +195,7 @@ public class Utils {
|
|||
builder.append("\">");
|
||||
builder.append(matcher.group(1));
|
||||
builder.append("</a>");
|
||||
line = line.substring(line.indexOf(")")+1);
|
||||
line = line.substring(line.indexOf(")") + 1);
|
||||
continue;
|
||||
}
|
||||
pattern = Pattern.compile("^(http.*)");
|
||||
|
@ -147,44 +206,45 @@ public class Utils {
|
|||
builder.append("\">");
|
||||
builder.append(matcher.group(1));
|
||||
builder.append("</a>");
|
||||
line = line.substring(matcher.group(1).length());
|
||||
String sub = matcher.group(1);
|
||||
if (sub != null) {
|
||||
line = line.substring(sub.length());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pattern = Pattern.compile("^[*_]{2}(.+)[*_]{2}");
|
||||
matcher = pattern.matcher(line);
|
||||
if (matcher.find()) {
|
||||
if(line.startsWith("*")) {
|
||||
if (line.startsWith("*")) {
|
||||
line = line.replaceFirst("\\*\\*", "<b>");
|
||||
formatStarter.add("**");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
line = line.replaceFirst("__", "<b>");
|
||||
formatStarter.add("__");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pattern = Pattern.compile("^[*_]{1}(.+)");
|
||||
pattern = Pattern.compile("^[*_](.+)");
|
||||
matcher = pattern.matcher(line);
|
||||
if (matcher.find()) {
|
||||
if(line.startsWith("*")) {
|
||||
if (line.startsWith("*")) {
|
||||
line = line.replaceFirst("\\*", "<i>");
|
||||
formatStarter.add("*");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
line = line.replaceFirst("_", "<i>");
|
||||
formatStarter.add("_");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(formatStarter.size() > 0) {
|
||||
if (formatStarter.size() > 0) {
|
||||
String checkFormat;
|
||||
if(line.contains(" "))
|
||||
checkFormat = line.substring(0,line.indexOf(" "));
|
||||
if (line.contains(" "))
|
||||
checkFormat = line.substring(0, line.indexOf(" "));
|
||||
else
|
||||
checkFormat = line;
|
||||
String lastFormat = formatStarter.get(formatStarter.size()-1);
|
||||
String lastFormat = formatStarter.get(formatStarter.size() - 1);
|
||||
if (checkFormat.contains(lastFormat)) {
|
||||
if(lastFormat.length()==2) {
|
||||
if (lastFormat.length() == 2) {
|
||||
if (lastFormat.contains("*"))
|
||||
line = line.replaceFirst("\\*\\*", "</b>");
|
||||
else
|
||||
|
@ -195,12 +255,12 @@ public class Utils {
|
|||
else
|
||||
line = line.replaceFirst("_", "</i>");
|
||||
}
|
||||
formatStarter.remove(formatStarter.size()-1);
|
||||
formatStarter.remove(formatStarter.size() - 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(line.contains(" ")) {
|
||||
if (line.contains(" ")) {
|
||||
builder.append(line.substring(0, line.indexOf(" ") + 1));
|
||||
line = line.substring(line.indexOf(" ") + 1);
|
||||
} else {
|
||||
|
@ -209,13 +269,13 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
//close all unclosed tags starting at the end
|
||||
while(!closeTags.isEmpty()) {
|
||||
builder.append(closeTags.remove(closeTags.size()-1));
|
||||
while (!closeTags.isEmpty()) {
|
||||
builder.append(closeTags.remove(closeTags.size() - 1));
|
||||
}
|
||||
builder.append("\n");
|
||||
|
||||
}
|
||||
while(!listStarter.isEmpty()) {
|
||||
while (!listStarter.isEmpty()) {
|
||||
listStarter.remove(listStarter.size() - 1);
|
||||
builder.append("</ul>\n");
|
||||
}
|
||||
|
|
|
@ -34,50 +34,34 @@ 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.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ApplicationListAdapter extends RecyclerView.Adapter {
|
||||
public class ApplicationListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private List<ApplicationViewModel> applicationViewModels;
|
||||
private OnAppClickListener onAppClickListener;
|
||||
private Object filter = "";
|
||||
private AppListFragment.Type filterType = AppListFragment.Type.NAME;
|
||||
private final OnAppClickListener onAppClickListener;
|
||||
private final int HIDDEN_APP = 0;
|
||||
private final int DISPLAYED_APP = 1;
|
||||
private List<ApplicationViewModel> applicationViewModels;
|
||||
private Object filter = "";
|
||||
private AppListFragment.Type filterType = AppListFragment.Type.NAME;
|
||||
private int displayedApp = 0;
|
||||
|
||||
private Comparator<ApplicationViewModel> alphaPackageComparator = new Comparator<ApplicationViewModel>() {
|
||||
@Override
|
||||
public int compare(ApplicationViewModel app1, ApplicationViewModel app2) {
|
||||
if(app1.label != null && app2.label != null)
|
||||
return app1.label.toString().compareToIgnoreCase(app2.label.toString());
|
||||
else if(app2.label != null)
|
||||
return -1;
|
||||
else if(app1.label != null)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
public ApplicationListAdapter(Context context, OnAppClickListener listener) {
|
||||
public ApplicationListAdapter(OnAppClickListener listener) {
|
||||
applicationViewModels = new ArrayList<>();
|
||||
onAppClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
public int getItemViewType(int position) {
|
||||
return applicationViewModels.get(position).isVisible ? DISPLAYED_APP : HIDDEN_APP;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
if( viewType == HIDDEN_APP)
|
||||
if (viewType == HIDDEN_APP)
|
||||
return new ApplicationEmptyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.app_item_empty, parent, false));
|
||||
else
|
||||
return new ApplicationListViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.app_item, parent, false));
|
||||
|
@ -86,18 +70,13 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
if( viewHolder.getItemViewType() == DISPLAYED_APP) {
|
||||
if (viewHolder.getItemViewType() == DISPLAYED_APP) {
|
||||
final ApplicationListViewHolder holder = (ApplicationListViewHolder) viewHolder;
|
||||
ApplicationViewModel vm = applicationViewModels.get(position);
|
||||
holder.setViewModel(vm);
|
||||
//noinspection Convert2Lambda
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onAppClickListener.onAppClick(vm);
|
||||
}
|
||||
});
|
||||
}else {
|
||||
holder.itemView.setOnClickListener(v -> onAppClickListener.onAppClick(vm));
|
||||
} else //noinspection RedundantSuppression
|
||||
{
|
||||
//noinspection unused
|
||||
final ApplicationEmptyViewHolder holder = (ApplicationEmptyViewHolder) viewHolder;
|
||||
//If something should be done for app that are hidden, it's here
|
||||
|
@ -111,15 +90,52 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
|||
|
||||
public void displayAppList(List<ApplicationViewModel> applications) {
|
||||
applicationViewModels = applications;
|
||||
Collections.sort(applicationViewModels, alphaPackageComparator);
|
||||
filter(filterType,filter);
|
||||
filter(filterType, filter);
|
||||
}
|
||||
|
||||
public int getDisplayedApps() {
|
||||
return displayedApp;
|
||||
}
|
||||
|
||||
static class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder{
|
||||
public void filter(AppListFragment.Type type, Object filterObject) {
|
||||
displayedApp = 0;
|
||||
if (type.equals(AppListFragment.Type.NAME)) {
|
||||
filter = filterObject;
|
||||
filterType = type;
|
||||
String filterStr = (String) filterObject;
|
||||
|
||||
Pattern p = Pattern.compile(Pattern.quote(filterStr.trim()), Pattern.CASE_INSENSITIVE);
|
||||
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();
|
||||
}
|
||||
|
||||
public interface OnAppClickListener {
|
||||
void onAppClick(ApplicationViewModel vm);
|
||||
}
|
||||
|
||||
static class ApplicationEmptyViewHolder extends RecyclerView.ViewHolder {
|
||||
ApplicationEmptyViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
@ -152,11 +168,11 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
|||
appItemBinding.appLogo.setImageDrawable(viewModel.icon);
|
||||
|
||||
appItemBinding.appName.setText(viewModel.label);
|
||||
appItemBinding.source.setText(context.getString(R.string.source,viewModel.source));
|
||||
appItemBinding.source.setText(context.getString(R.string.source, viewModel.source));
|
||||
|
||||
long size = viewModel.requestedPermissions != null ? viewModel.requestedPermissions.length : 0;
|
||||
appItemBinding.appPermissionNb.setText(String.valueOf(size));
|
||||
if(size == 0)
|
||||
if (size == 0)
|
||||
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_green);
|
||||
else if (size < 5)
|
||||
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_light_yellow);
|
||||
|
@ -164,24 +180,24 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
|||
appItemBinding.appPermissionNb.setBackgroundResource(R.drawable.square_light_red);
|
||||
|
||||
Report report = viewModel.report;
|
||||
if(report != null) {
|
||||
if (report != null) {
|
||||
Set<Tracker> trackers = viewModel.trackers;
|
||||
|
||||
size = trackers.size();
|
||||
appItemBinding.appTrackerNb.setText(String.valueOf(size));
|
||||
if(size == 0)
|
||||
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);
|
||||
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));
|
||||
String string = context.getString(R.string.tested, String.valueOf(versionCode), String.valueOf(report.versionCode));
|
||||
appItemBinding.otherVersion.setText(string);
|
||||
appItemBinding.otherVersion.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
@ -192,42 +208,4 @@ public class ApplicationListAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnAppClickListener {
|
||||
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;
|
||||
|
||||
Pattern p = Pattern.compile(Pattern.quote(filterStr.trim()), Pattern.CASE_INSENSITIVE);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ import org.eu.exodus_privacy.exodusprivacy.objects.Permission;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.TrackerListViewHolder>{
|
||||
public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAdapter.TrackerListViewHolder> {
|
||||
|
||||
private List<Permission> permissionList;
|
||||
|
||||
|
@ -25,13 +25,13 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
|||
@NonNull
|
||||
@Override
|
||||
public PermissionListAdapter.TrackerListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
PermissionItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.permission_item,parent,false);
|
||||
PermissionItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.permission_item, parent, false);
|
||||
return new TrackerListViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull PermissionListAdapter.TrackerListViewHolder holder, int position) {
|
||||
if(permissionList == null || permissionList.size() == 0)
|
||||
if (permissionList == null || permissionList.size() == 0)
|
||||
holder.setupData(null);
|
||||
else
|
||||
holder.setupData(permissionList.get(position));
|
||||
|
@ -39,7 +39,7 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
|||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if(permissionList == null || permissionList.size() == 0)
|
||||
if (permissionList == null || permissionList.size() == 0)
|
||||
return 0;
|
||||
else
|
||||
return permissionList.size();
|
||||
|
@ -50,7 +50,7 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
|||
}
|
||||
|
||||
|
||||
class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
||||
static class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
PermissionItemBinding permissionItemBinding;
|
||||
|
||||
|
@ -60,32 +60,30 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
|||
}
|
||||
|
||||
void setupData(Permission permission) {
|
||||
if(permission != null) {
|
||||
if(permission.name != null) {
|
||||
if (permission != null) {
|
||||
if (permission.name != null) {
|
||||
permissionItemBinding.permissionShort.setText(permission.name);
|
||||
permissionItemBinding.permissionShort.setVisibility(View.VISIBLE);
|
||||
}
|
||||
else
|
||||
} else
|
||||
permissionItemBinding.permissionShort.setVisibility(View.GONE);
|
||||
|
||||
permissionItemBinding.permissionName.setText(permission.fullName.substring(permission.fullName.lastIndexOf(".")+1));
|
||||
permissionItemBinding.permissionName.setText(permission.fullName.substring(permission.fullName.lastIndexOf(".") + 1));
|
||||
permissionItemBinding.permissionDescription.setText(permission.description);
|
||||
if(permission.icon != null)
|
||||
if (permission.icon != null)
|
||||
permissionItemBinding.icon.setImageDrawable(permission.icon);
|
||||
if(!permission.dangerous)
|
||||
if (!permission.dangerous)
|
||||
permissionItemBinding.dangerous.setVisibility(View.GONE);
|
||||
else
|
||||
permissionItemBinding.dangerous.setVisibility(View.VISIBLE);
|
||||
manageExpanded(permission);
|
||||
permissionItemBinding.mainLayout.setOnClickListener((View.OnClickListener) v -> {
|
||||
if( permission.description != null && permission.description.trim().length() > 0) {
|
||||
permissionItemBinding.mainLayout.setOnClickListener(v -> {
|
||||
if (permission.description != null && permission.description.trim().length() > 0) {
|
||||
permission.expanded = !permission.expanded;
|
||||
manageExpanded(permission);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
permissionItemBinding.permissionName.setText(R.string.no_permissions);
|
||||
permissionItemBinding.arrow.setText(" ");
|
||||
permissionItemBinding.permissionShort.setVisibility(View.GONE);
|
||||
|
@ -96,11 +94,11 @@ public class PermissionListAdapter extends RecyclerView.Adapter<PermissionListAd
|
|||
}
|
||||
|
||||
void manageExpanded(Permission permission) {
|
||||
if(permission.expanded) {
|
||||
if (permission.expanded) {
|
||||
permissionItemBinding.arrow.setText("▼");
|
||||
permissionItemBinding.permissionDescription.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if( permission.description != null && permission.description.trim().length() > 0 )
|
||||
if (permission.description != null && permission.description.trim().length() > 0)
|
||||
permissionItemBinding.arrow.setText("▶");
|
||||
else
|
||||
permissionItemBinding.arrow.setText("");
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.adapters;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
@ -20,11 +19,12 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.TrackerListViewHolder>{
|
||||
public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.TrackerListViewHolder> {
|
||||
|
||||
private final OnTrackerClickListener trackerClickListener;
|
||||
private final int layout;
|
||||
private final Comparator<Tracker> alphaTrackerComparator = (track1, track2) -> track1.name.compareToIgnoreCase(track2.name);
|
||||
private List<Tracker> trackersList;
|
||||
private OnTrackerClickListener trackerClickListener;
|
||||
private int layout;
|
||||
|
||||
public TrackerListAdapter(Set<Tracker> trackerList, int resource, OnTrackerClickListener listener) {
|
||||
setTrackers(trackerList);
|
||||
|
@ -35,13 +35,13 @@ public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.
|
|||
@NonNull
|
||||
@Override
|
||||
public TrackerListAdapter.TrackerListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),layout,parent,false);
|
||||
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), layout, parent, false);
|
||||
return new TrackerListViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull TrackerListAdapter.TrackerListViewHolder holder, int position) {
|
||||
if(trackersList == null || trackersList.size() == 0)
|
||||
if (trackersList == null || trackersList.size() == 0)
|
||||
holder.setupData(null);
|
||||
else
|
||||
holder.setupData(trackersList.get(position));
|
||||
|
@ -49,21 +49,23 @@ public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.
|
|||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if(trackersList == null || trackersList.size() == 0)
|
||||
if (trackersList == null || trackersList.size() == 0)
|
||||
return 1;
|
||||
else
|
||||
return trackersList.size();
|
||||
}
|
||||
|
||||
private Comparator<Tracker> alphaTrackerComparator = (track1, track2) -> track1.name.compareToIgnoreCase(track2.name);
|
||||
|
||||
public void setTrackers(Set<Tracker> trackers) {
|
||||
if(trackers != null) {
|
||||
if (trackers != null) {
|
||||
trackersList = new ArrayList<>(trackers);
|
||||
Collections.sort(trackersList, alphaTrackerComparator);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTrackerClickListener {
|
||||
void onTrackerClick(long trackerId);
|
||||
}
|
||||
|
||||
class TrackerListViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ViewDataBinding viewDataBinding;
|
||||
|
@ -74,23 +76,16 @@ public class TrackerListAdapter extends RecyclerView.Adapter<TrackerListAdapter.
|
|||
}
|
||||
|
||||
void setupData(Tracker tracker) {
|
||||
if(viewDataBinding instanceof TrackerItemBinding) {
|
||||
if (viewDataBinding instanceof TrackerItemBinding) {
|
||||
TrackerItemBinding binding = (TrackerItemBinding) viewDataBinding;
|
||||
if(tracker != null) {
|
||||
binding.trackerName.setText(tracker.name + " ➤");
|
||||
binding.getRoot().setOnClickListener(v -> {
|
||||
trackerClickListener.onTrackerClick(tracker.id);
|
||||
});
|
||||
}
|
||||
else
|
||||
if (tracker != null) {
|
||||
binding.trackerName.setText(String.format("%s ➤", tracker.name));
|
||||
binding.getRoot().setOnClickListener(v -> trackerClickListener.onTrackerClick(tracker.id));
|
||||
} else
|
||||
binding.trackerName.setText(R.string.no_trackers);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnTrackerClickListener{
|
||||
public void onTrackerClick(long trackerId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.List;
|
|||
|
||||
public class AppListFragment extends Fragment {
|
||||
|
||||
|
||||
private ApplistBinding applistBinding;
|
||||
private List<ApplicationViewModel> applications;
|
||||
private ApplicationListAdapter adapter;
|
||||
|
@ -32,36 +33,38 @@ public class AppListFragment extends Fragment {
|
|||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
//create binding
|
||||
applistBinding = DataBindingUtil.inflate(inflater, R.layout.applist,container,false);
|
||||
applistBinding = DataBindingUtil.inflate(inflater, R.layout.applist, container, false);
|
||||
//init variables
|
||||
if (applications == null)
|
||||
applications = new ArrayList<>();
|
||||
Context context = applistBinding.getRoot().getContext();
|
||||
//configure list
|
||||
applistBinding.appList.setLayoutManager(new LinearLayoutManager(context));
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
|
||||
applistBinding.appList.setLayoutManager(linearLayoutManager);
|
||||
applistBinding.appList.setVerticalScrollBarEnabled(scrollbarEnabled);
|
||||
adapter = new ApplicationListAdapter(context, onAppClickListener);
|
||||
adapter = new ApplicationListAdapter(onAppClickListener);
|
||||
adapter.displayAppList(applications);
|
||||
adapter.filter(filterType,filterObject);
|
||||
adapter.filter(filterType, filterObject);
|
||||
applistBinding.appList.setAdapter(adapter);
|
||||
return applistBinding.getRoot();
|
||||
}
|
||||
|
||||
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener listener){
|
||||
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener listener) {
|
||||
onAppClickListener = listener;
|
||||
}
|
||||
|
||||
public void setApplications(List<ApplicationViewModel> applicationList){
|
||||
|
||||
public void setApplications(List<ApplicationViewModel> applicationList) {
|
||||
applications = applicationList;
|
||||
if(adapter != null)
|
||||
if (adapter != null)
|
||||
adapter.displayAppList(applications);
|
||||
}
|
||||
|
||||
public void setFilter(Type type, Object filter){
|
||||
public void setFilter(Type type, Object filter) {
|
||||
filterType = type;
|
||||
filterObject = filter;
|
||||
if(adapter != null)
|
||||
adapter.filter(type,filterObject);
|
||||
if (adapter != null)
|
||||
adapter.filter(type, filterObject);
|
||||
}
|
||||
|
||||
public void disableScrollBar() {
|
||||
|
@ -70,6 +73,7 @@ public class AppListFragment extends Fragment {
|
|||
applistBinding.appList.setVerticalScrollBarEnabled(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused", "RedundantSuppression"})
|
||||
public void enableScrollBar() {
|
||||
scrollbarEnabled = true;
|
||||
if (applistBinding != null)
|
||||
|
@ -88,17 +92,9 @@ public class AppListFragment extends Fragment {
|
|||
return adapter.getDisplayedApps();
|
||||
}
|
||||
|
||||
|
||||
public enum Type {
|
||||
NAME,
|
||||
TRACKER
|
||||
}
|
||||
|
||||
public enum Order {
|
||||
NAME_ASC,
|
||||
NAME_DSC,
|
||||
TRACKER_ASC,
|
||||
TRACKER_DSC,
|
||||
PERMISSIONS_ASC,
|
||||
PERMISSIONS_DSC
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
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.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ComputeAppList {
|
||||
|
||||
private static final String gStore = "com.android.vending";
|
||||
private static final String fdroid = "org.fdroid.fdroid";
|
||||
|
||||
|
||||
public static List<ApplicationViewModel> compute(PackageManager packageManager,
|
||||
DatabaseManager databaseManager, order userOrderChoice) {
|
||||
|
||||
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;
|
||||
}
|
||||
order(vms, userOrderChoice);
|
||||
return vms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter List<ApplicationViewModel> with one of criteria of order
|
||||
*
|
||||
* @param vms List<ApplicationViewModel>
|
||||
* @param orderChoice order
|
||||
*/
|
||||
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));
|
||||
} 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)));
|
||||
}
|
||||
}
|
||||
|
||||
private static 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static 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 static 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,138 +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.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,15 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
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.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -17,18 +22,24 @@ 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.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 org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HomeFragment extends Fragment implements ComputeAppListTask.Listener, Updatable {
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
public class HomeFragment extends Fragment implements ComputeAppList.Listener, Updatable {
|
||||
|
||||
private @Nullable
|
||||
PackageManager packageManager;
|
||||
|
@ -41,48 +52,56 @@ public class HomeFragment extends Fragment implements ComputeAppListTask.Listene
|
|||
private boolean startRefreshAsked;
|
||||
private boolean refreshInProgress;
|
||||
|
||||
private int lastResource=0;
|
||||
private int lastProgress=0;
|
||||
private int lastMaxProgress=0;
|
||||
private int lastResource = 0;
|
||||
private int lastProgress = 0;
|
||||
private int lastMaxProgress = 0;
|
||||
private String last_refresh;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
if(applications == null)
|
||||
if (applications == null)
|
||||
applications = new ArrayList<>();
|
||||
homeBinding = DataBindingUtil.inflate(inflater, R.layout.home,container,false);
|
||||
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.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) {
|
||||
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(Utils.APP_PREFS, MODE_PRIVATE);
|
||||
last_refresh = sharedPreferences.getString(Utils.LAST_REFRESH, null);
|
||||
|
||||
if (packageManager != null) {
|
||||
homeBinding.noPackageManager.setVisibility(View.GONE);
|
||||
|
||||
onAppsComputed(applications);
|
||||
if(applications.isEmpty())
|
||||
displayAppListAsync();
|
||||
if(startRefreshAsked)
|
||||
if (applications.isEmpty())
|
||||
displayAppListAsync(null);
|
||||
if (startRefreshAsked && last_refresh == null)
|
||||
startRefresh();
|
||||
else if (refreshInProgress) {
|
||||
homeBinding.layoutProgress.setVisibility(View.VISIBLE);
|
||||
homeBinding.swipeRefresh.setRefreshing(true);
|
||||
updateProgress(lastResource,lastProgress,lastMaxProgress);
|
||||
updateProgress(lastResource, lastProgress, lastMaxProgress);
|
||||
}
|
||||
|
||||
} else {
|
||||
homeBinding.noPackageManager.setVisibility(View.VISIBLE);
|
||||
}
|
||||
return homeBinding.getRoot();
|
||||
}
|
||||
|
||||
public void startRefresh(){
|
||||
if(packageManager != null) {
|
||||
|
||||
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);
|
||||
|
@ -94,19 +113,28 @@ public class HomeFragment extends Fragment implements ComputeAppListTask.Listene
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (!refreshInProgress && homeBinding.layoutProgress.getVisibility() == View.VISIBLE) {
|
||||
onUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onUpdateComplete() {
|
||||
refreshInProgress = false;
|
||||
homeBinding.layoutProgress.setVisibility(View.GONE);
|
||||
homeBinding.swipeRefresh.setRefreshing(false);
|
||||
displayAppListAsync();
|
||||
displayAppListAsync(null);
|
||||
}
|
||||
|
||||
public void setNetworkListener(NetworkListener listener) {
|
||||
this.networkListener = new NetworkListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
listener.onSuccess();
|
||||
public void onSuccess(Application application) {
|
||||
listener.onSuccess(application);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -124,16 +152,16 @@ public class HomeFragment extends Fragment implements ComputeAppListTask.Listene
|
|||
lastResource = resourceId;
|
||||
lastProgress = progress;
|
||||
lastMaxProgress = maxProgress;
|
||||
if(lastResource == 0)
|
||||
if (lastResource == 0)
|
||||
return;
|
||||
Activity activity = getActivity();
|
||||
if(activity == null)
|
||||
if (activity == null)
|
||||
return;
|
||||
activity.runOnUiThread(() -> {
|
||||
if (homeBinding == null)
|
||||
return;
|
||||
if(maxProgress > 0)
|
||||
homeBinding.statusProgress.setText(activity.getString(resourceId)+" "+progress+"/"+maxProgress);//fixme
|
||||
if (maxProgress > 0)
|
||||
homeBinding.statusProgress.setText(String.format(Locale.getDefault(), "%s %d/%d", activity.getString(resourceId), progress, maxProgress));
|
||||
else
|
||||
homeBinding.statusProgress.setText(activity.getString(resourceId));
|
||||
homeBinding.progress.setMax(maxProgress);
|
||||
|
@ -144,26 +172,27 @@ public class HomeFragment extends Fragment implements ComputeAppListTask.Listene
|
|||
|
||||
public void setOnAppClickListener(ApplicationListAdapter.OnAppClickListener onAppClickListener) {
|
||||
this.onAppClickListener = onAppClickListener;
|
||||
if(appListFragment != null)
|
||||
if (appListFragment != null)
|
||||
appListFragment.setOnAppClickListener(onAppClickListener);
|
||||
}
|
||||
|
||||
public void filter(String filter){
|
||||
appListFragment.setFilter(AppListFragment.Type.NAME,filter);
|
||||
public void filter(String filter) {
|
||||
appListFragment.setFilter(AppListFragment.Type.NAME, filter);
|
||||
}
|
||||
|
||||
private void displayAppListAsync() {
|
||||
public void displayAppListAsync(ComputeAppList.order orderList) {
|
||||
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();
|
||||
new Thread(() -> {
|
||||
List<ApplicationViewModel> vms = ComputeAppList.compute(packageManager, DatabaseManager.getInstance(getActivity()), orderList);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> onAppsComputed(vms);
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -173,9 +202,29 @@ public class HomeFragment extends Fragment implements ComputeAppListTask.Listene
|
|||
homeBinding.logo.setVisibility(View.GONE);
|
||||
homeBinding.noAppFound.setVisibility(apps.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
appListFragment.setApplications(apps);
|
||||
if(!apps.isEmpty()) {
|
||||
if(startupRefresh) {
|
||||
startRefresh();
|
||||
if (!apps.isEmpty()) {
|
||||
if (startupRefresh) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
if (last_refresh != null) {
|
||||
cal.setTime(Utils.stringToDate(getContext(), last_refresh));
|
||||
cal.add(Calendar.DAY_OF_YEAR, 1);
|
||||
}
|
||||
Date refreshAfter = cal.getTime();
|
||||
Date currentDate = new Date();
|
||||
if (last_refresh != null && !refreshInProgress && currentDate.after(refreshAfter)) {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext());
|
||||
dialogBuilder.setMessage(getString(R.string.refresh_needed_message, last_refresh));
|
||||
dialogBuilder.setPositiveButton(R.string.refresh, (dialog, id) -> {
|
||||
startRefresh();
|
||||
dialog.dismiss();
|
||||
});
|
||||
dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
AlertDialog alertDialog = dialogBuilder.create();
|
||||
alertDialog.show();
|
||||
|
||||
} else if (last_refresh == null) {
|
||||
startRefresh();
|
||||
}
|
||||
startupRefresh = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ import android.os.Bundle;
|
|||
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;
|
||||
|
||||
|
@ -37,14 +36,17 @@ import androidx.databinding.DataBindingUtil;
|
|||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.BuildConfig;
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.ReportViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.ApplicationViewModel;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.PermissionListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.adapters.TrackerListAdapter;
|
||||
import org.eu.exodus_privacy.exodusprivacy.databinding.ReportBinding;
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.ReportDisplay;
|
||||
public class ReportFragment extends Fragment implements Updatable {
|
||||
|
||||
public class ReportFragment extends Fragment implements Updatable {
|
||||
|
||||
private PackageManager packageManager;
|
||||
private PackageInfo packageInfo = null;
|
||||
|
@ -52,7 +54,7 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
private TrackerListAdapter.OnTrackerClickListener trackerClickListener;
|
||||
private ApplicationViewModel model;
|
||||
|
||||
public static ReportFragment newInstance(PackageManager packageManager,ApplicationViewModel model, PackageInfo packageInfo, TrackerListAdapter.OnTrackerClickListener trackerClickListener) {
|
||||
public static ReportFragment newInstance(PackageManager packageManager, ApplicationViewModel model, PackageInfo packageInfo, TrackerListAdapter.OnTrackerClickListener trackerClickListener) {
|
||||
ReportFragment fragment = new ReportFragment();
|
||||
fragment.setPackageManager(packageManager);
|
||||
fragment.setPackageInfo(packageInfo);
|
||||
|
@ -68,7 +70,7 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if(savedInstanceState != null && packageInfo == null) {
|
||||
if (savedInstanceState != null && packageInfo == null) {
|
||||
packageInfo = savedInstanceState.getParcelable("PackageInfo");
|
||||
}
|
||||
setHasOptionsMenu(true);
|
||||
|
@ -81,22 +83,22 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
reportBinding = DataBindingUtil.inflate(inflater,R.layout.report,container,false);
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
reportBinding = DataBindingUtil.inflate(inflater, R.layout.report, container, false);
|
||||
onUpdateComplete();
|
||||
return reportBinding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateComplete() {
|
||||
if(model != null)
|
||||
if (model != null)
|
||||
onUpdateComplete(model);
|
||||
}
|
||||
|
||||
public void onUpdateComplete(ApplicationViewModel model) {
|
||||
Context context = reportBinding.getRoot().getContext();
|
||||
|
||||
ReportDisplay reportDisplay = ReportDisplay.buildReportDisplay(context,model,packageManager,packageInfo);
|
||||
ReportDisplay reportDisplay = ReportDisplay.buildReportDisplay(context, model, packageManager, packageInfo);
|
||||
ReportViewModel viewModel = new ReportViewModel();
|
||||
viewModel.setReportDisplay(reportDisplay);
|
||||
reportBinding.setReportInfo(viewModel);
|
||||
|
@ -110,7 +112,7 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
|
||||
//setup trackers lists
|
||||
reportBinding.trackers.setLayoutManager(new LinearLayoutManager(context));
|
||||
TrackerListAdapter trackerAdapter = new TrackerListAdapter(reportDisplay.trackers,R.layout.tracker_item, trackerClickListener);
|
||||
TrackerListAdapter trackerAdapter = new TrackerListAdapter(reportDisplay.trackers, R.layout.tracker_item, trackerClickListener);
|
||||
reportBinding.trackers.setNestedScrollingEnabled(false);
|
||||
reportBinding.trackers.setAdapter(trackerAdapter);
|
||||
|
||||
|
@ -133,17 +135,28 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
|
||||
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));
|
||||
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));
|
||||
intent.setData(Uri.parse("https://f-droid.org/packages/" + reportDisplay.packageName));
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
if(reportDisplay.report != null) {
|
||||
reportBinding.analyseApp.setOnClickListener(v -> {
|
||||
Uri uri;
|
||||
if (!BuildConfig.amal) {
|
||||
uri = Uri.parse("https://reports.exodus-privacy.eu.org/analysis/submit/#" + reportDisplay.packageName);
|
||||
} else {
|
||||
uri = Uri.parse("https://exodus.phm.education.gouv.fr/analysis/submit/#" + reportDisplay.packageName);
|
||||
}
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(browserIntent);
|
||||
});
|
||||
|
||||
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 + "/"));
|
||||
intent.setData(Uri.parse("https://" + Utils.getDomain() + "/reports/" + reportDisplay.report.id + "/"));
|
||||
startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
@ -163,8 +176,9 @@ public class ReportFragment extends Fragment implements Updatable {
|
|||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
MenuItem item = menu.findItem(R.id.action_filter);
|
||||
item.setVisible(false);
|
||||
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() {
|
||||
|
|
|
@ -5,14 +5,16 @@ import android.content.Intent;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
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.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
@ -27,11 +29,10 @@ 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 {
|
||||
public class TrackerFragment extends Fragment implements ComputeAppList.Listener, Updatable {
|
||||
|
||||
private TrackerBinding trackerBinding;
|
||||
private long trackerId;
|
||||
|
@ -75,17 +76,17 @@ public class TrackerFragment extends Fragment implements ComputeAppListTask.List
|
|||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
trackerBinding = DataBindingUtil.inflate(inflater, R.layout.tracker,container,false);
|
||||
public View onCreateView(@NonNull 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.setFilter(AppListFragment.Type.TRACKER, trackerId);
|
||||
appListFragment.disableScrollBar();
|
||||
appListFragment.setOnAppClickListener(onAppClickListener);
|
||||
FragmentManager manager = getChildFragmentManager();
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
transaction.replace(R.id.applications,appListFragment);
|
||||
transaction.replace(R.id.applications, appListFragment);
|
||||
transaction.commit();
|
||||
Context context = trackerBinding.getRoot().getContext();
|
||||
packageManager = context.getPackageManager();
|
||||
|
@ -96,11 +97,9 @@ public class TrackerFragment extends Fragment implements ComputeAppListTask.List
|
|||
|
||||
@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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void displayAppListAsync() {
|
||||
|
@ -114,14 +113,14 @@ public class TrackerFragment extends Fragment implements ComputeAppListTask.List
|
|||
trackerBinding.retrieveApp.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
new ComputeAppListTask(
|
||||
new WeakReference<>(packageManager),
|
||||
new WeakReference<>(DatabaseManager.getInstance(getActivity())),
|
||||
new WeakReference<>(this)
|
||||
).execute();
|
||||
new Thread(() -> {
|
||||
List<ApplicationViewModel> vms = ComputeAppList.compute(packageManager, DatabaseManager.getInstance(getActivity()), null);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
Runnable myRunnable = () -> onAppsComputed(vms);
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppsComputed(List<ApplicationViewModel> apps) {
|
||||
this.applications = apps;
|
||||
trackerBinding.retrieveApp.setVisibility(View.GONE);
|
||||
|
@ -132,19 +131,19 @@ public class TrackerFragment extends Fragment implements ComputeAppListTask.List
|
|||
appListFragment.setApplications(apps);
|
||||
int total = appListFragment.getTotalApps();
|
||||
int displayedApps = appListFragment.getDisplayedApps();
|
||||
int percent = displayedApps*100/total;
|
||||
if(percent >=50)
|
||||
int percent = displayedApps * 100 / total;
|
||||
if (percent >= 50)
|
||||
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_red);
|
||||
else if(percent >=33)
|
||||
else if (percent >= 33)
|
||||
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_dark_orange);
|
||||
else if(percent >=20)
|
||||
else if (percent >= 20)
|
||||
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_yellow);
|
||||
else
|
||||
trackerBinding.trackerPresenceNb.setBackgroundResource(R.drawable.square_light_blue);
|
||||
|
||||
trackerBinding.trackerPresenceNb.setText(percent+"%");
|
||||
trackerBinding.trackerPresenceNb.setText(String.format("%s%%", percent));
|
||||
Context context = trackerBinding.getRoot().getContext();
|
||||
String presence = context.getResources().getString(R.string.tracker_presence,displayedApps);
|
||||
String presence = context.getResources().getString(R.string.tracker_presence, displayedApps);
|
||||
trackerBinding.trackerPresence.setText(presence);
|
||||
trackerBinding.trackerPresenceTitle.setText(R.string.tracker_presence_in);
|
||||
}
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
|
||||
package org.eu.exodus_privacy.exodusprivacy.listener;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.objects.Application;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
|
||||
/*
|
||||
Listener working with the NetworkManager to handle events
|
||||
*/
|
||||
public interface NetworkListener extends EventListener{
|
||||
void onSuccess();
|
||||
public interface NetworkListener extends EventListener {
|
||||
void onSuccess(Application application);
|
||||
|
||||
void onError(String error);
|
||||
|
||||
void onProgress(int resourceId, int progress, int maxProgress);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ 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 java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -45,8 +46,8 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
|
||||
|
||||
public static DatabaseManager getInstance(Context context) {
|
||||
if(instance == null)
|
||||
instance = new DatabaseManager(context,"Exodus.db",null,3);
|
||||
if (instance == null)
|
||||
instance = new DatabaseManager(context, "Exodus.db", null, 3);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if(oldVersion <= 1) {
|
||||
if (oldVersion <= 1) {
|
||||
db.execSQL("Alter Table applications add column auid TEXT");
|
||||
}
|
||||
if (oldVersion <= 2) {
|
||||
|
@ -71,15 +72,15 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
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()){
|
||||
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);
|
||||
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");
|
||||
|
@ -94,53 +95,52 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
private boolean existReport(SQLiteDatabase db, long reportId) {
|
||||
return exist(db,"reports",reportId);
|
||||
return exist(db, "reports", reportId);
|
||||
}
|
||||
|
||||
private boolean existApplication(SQLiteDatabase db, String packageName) {
|
||||
String[] columns = {"package"};
|
||||
String where = "package = ?";
|
||||
String[] whereArgs = {packageName};
|
||||
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||
Cursor cursor = db.query("applications", columns, where, whereArgs, null, null, null);
|
||||
boolean exist = cursor.getCount() != 0;
|
||||
cursor.close();
|
||||
return exist;
|
||||
}
|
||||
|
||||
private boolean existTracker(SQLiteDatabase db, long trackerId) {
|
||||
return exist(db,"trackers",trackerId);
|
||||
return exist(db, "trackers", trackerId);
|
||||
}
|
||||
|
||||
private boolean exist(SQLiteDatabase db, String table, long id) {
|
||||
if(id == -1)
|
||||
if (id == -1)
|
||||
return false;
|
||||
String[] columns = {"id"};
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(id)};
|
||||
Cursor cursor = db.query(table,columns,where,whereArgs,null,null,null);
|
||||
Cursor cursor = db.query(table, columns, where, whereArgs, null, null, null);
|
||||
boolean exist = cursor.getCount() != 0;
|
||||
cursor.close();
|
||||
return exist;
|
||||
}
|
||||
|
||||
private void insertOrUpdateTracker(SQLiteDatabase db,Tracker tracker) {
|
||||
private void insertOrUpdateTracker(SQLiteDatabase db, Tracker tracker) {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
values.put("name",tracker.name);
|
||||
values.put("code_signature",tracker.codeSignature);
|
||||
values.put("network_signature",tracker.networkSignature);
|
||||
values.put("website",tracker.website);
|
||||
values.put("description",tracker.description);
|
||||
values.put("creation_date",tracker.creationDate.getTimeInMillis());
|
||||
values.put("name", tracker.name);
|
||||
values.put("code_signature", tracker.codeSignature);
|
||||
values.put("network_signature", tracker.networkSignature);
|
||||
values.put("website", tracker.website);
|
||||
values.put("description", tracker.description);
|
||||
values.put("creation_date", tracker.creationDate.getTimeInMillis());
|
||||
|
||||
if(!existTracker(db,tracker.id)) {
|
||||
values.put("id",tracker.id);
|
||||
if (!existTracker(db, tracker.id)) {
|
||||
values.put("id", tracker.id);
|
||||
db.insert("trackers", null, values);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(tracker.id)};
|
||||
db.update("trackers",values,where,whereArgs);
|
||||
db.update("trackers", values, where, whereArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,54 +148,53 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("package", application.packageName);
|
||||
values.put("name",application.name);
|
||||
values.put("creator",application.creator);
|
||||
values.put("sources",buildSourcesStr(application.sources));
|
||||
values.put("name", application.name);
|
||||
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);
|
||||
} else {
|
||||
String where = "package = ?";
|
||||
String[] whereArgs = {application.packageName};
|
||||
db.update("applications",values,where,whereArgs);
|
||||
db.update("applications", values, where, whereArgs);
|
||||
}
|
||||
|
||||
String[] columns = {"id"};
|
||||
String where = "package = ?";
|
||||
String[] whereArgs = {application.packageName};
|
||||
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||
if(cursor.moveToFirst()) {
|
||||
Cursor cursor = db.query("applications", columns, where, whereArgs, null, null, null);
|
||||
if (cursor.moveToFirst()) {
|
||||
application.id = cursor.getLong(0);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
for(Report report : application.reports) {
|
||||
insertOrUpdateReport(db,report,application.id);
|
||||
for (Report report : application.reports) {
|
||||
insertOrUpdateReport(db, report, application.id);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertOrUpdateReport(SQLiteDatabase db, Report report, long appId) {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
values.put("creation",report.creationDate.getTimeInMillis());
|
||||
values.put("updateat",report.updateDate.getTimeInMillis());
|
||||
values.put("downloads",report.downloads);
|
||||
values.put("version",report.version);
|
||||
values.put("version_code",report.versionCode);
|
||||
values.put("app_id",appId);
|
||||
values.put("source",report.source);
|
||||
values.put("creation", report.creationDate.getTimeInMillis());
|
||||
values.put("updateat", report.updateDate.getTimeInMillis());
|
||||
values.put("downloads", report.downloads);
|
||||
values.put("version", report.version);
|
||||
values.put("version_code", report.versionCode);
|
||||
values.put("app_id", appId);
|
||||
values.put("source", report.source);
|
||||
|
||||
if(!existReport(db,report.id)) {
|
||||
values.put("id",report.id);
|
||||
if (!existReport(db, report.id)) {
|
||||
values.put("id", report.id);
|
||||
db.insert("reports", null, values);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(report.id)};
|
||||
db.update("reports",values,where,whereArgs);
|
||||
db.update("reports", values, where, whereArgs);
|
||||
}
|
||||
removeTrackers(report.id);
|
||||
for(Long tracker : report.trackers) {
|
||||
for (Long tracker : report.trackers) {
|
||||
insertTrackerReport(db, tracker, report.id);
|
||||
}
|
||||
}
|
||||
|
@ -203,14 +202,14 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
private void removeTrackers(long reportId) {
|
||||
String where = "report_id = ?";
|
||||
String[] whereArgs = {String.valueOf(reportId)};
|
||||
getWritableDatabase().delete("trackers_reports",where,whereArgs);
|
||||
getWritableDatabase().delete("trackers_reports", where, whereArgs);
|
||||
}
|
||||
|
||||
private void insertTrackerReport(SQLiteDatabase db, long trackerId, long reportId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("report_id",reportId);
|
||||
values.put("tracker_id",trackerId);
|
||||
db.insert("trackers_reports",null,values);
|
||||
values.put("report_id", reportId);
|
||||
values.put("tracker_id", trackerId);
|
||||
db.insert("trackers_reports", null, values);
|
||||
}
|
||||
|
||||
public Report getReportFor(String packageName, String version, String source) {
|
||||
|
@ -218,34 +217,48 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
String[] columns = {"id"};
|
||||
String where = "package = ?";
|
||||
String[] whereArgs = {packageName};
|
||||
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||
if(cursor.moveToFirst()) {
|
||||
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 = ? 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);
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
long reportId;
|
||||
if(cursor.moveToFirst()) {
|
||||
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;
|
||||
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);
|
||||
if(cursor.moveToFirst()) {
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
if (cursor.moveToFirst()) {
|
||||
reportId = cursor.getLong(0);
|
||||
cursor.close();
|
||||
} else {
|
||||
|
@ -266,8 +279,8 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
String[] columns = {"id"};
|
||||
String where = "package = ?";
|
||||
String[] whereArgs = {packageName};
|
||||
Cursor cursor = db.query("applications",columns,where,whereArgs,null,null,null);
|
||||
if(cursor.moveToFirst()) {
|
||||
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 = ?";
|
||||
|
@ -276,9 +289,9 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
whereArgs[1] = String.valueOf(version);
|
||||
whereArgs[2] = source;
|
||||
String order = "id ASC";
|
||||
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
long reportId;
|
||||
if(cursor.moveToFirst()) {
|
||||
if (cursor.moveToFirst()) {
|
||||
reportId = cursor.getLong(0);
|
||||
cursor.close();
|
||||
} else {
|
||||
|
@ -292,8 +305,8 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
whereArgs[1] = source;
|
||||
order = "creation DESC";
|
||||
//search a recent reports
|
||||
cursor = db.query("reports",columns,where,whereArgs,null,null,order);
|
||||
if(cursor.moveToFirst()) {
|
||||
cursor = db.query("reports", columns, where, whereArgs, null, null, order);
|
||||
if (cursor.moveToFirst()) {
|
||||
reportId = cursor.getLong(0);
|
||||
cursor.close();
|
||||
} else {
|
||||
|
@ -313,9 +326,9 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
SQLiteDatabase db = getReadableDatabase();
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(reportId)};
|
||||
Cursor cursor = db.query("reports",null,where,whereArgs,null,null,null);
|
||||
Cursor cursor = db.query("reports", null, where, whereArgs, null, null, null);
|
||||
//get report
|
||||
if(!cursor.moveToFirst()) {
|
||||
if (!cursor.moveToFirst()) {
|
||||
cursor.close();
|
||||
return null;
|
||||
}
|
||||
|
@ -326,11 +339,11 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
long creation = cursor.getLong(col++);
|
||||
report.creationDate = Calendar.getInstance();
|
||||
report.creationDate.setTimeInMillis(creation);
|
||||
report.creationDate.set(Calendar.MILLISECOND,0);
|
||||
report.creationDate.set(Calendar.MILLISECOND, 0);
|
||||
long update = cursor.getLong(col++);
|
||||
report.updateDate = Calendar.getInstance();
|
||||
report.updateDate.setTimeInMillis(update);
|
||||
report.updateDate.set(Calendar.MILLISECOND,0);
|
||||
report.updateDate.set(Calendar.MILLISECOND, 0);
|
||||
report.downloads = cursor.getString(col++);
|
||||
report.version = cursor.getString(col++);
|
||||
report.versionCode = cursor.getLong(col++);
|
||||
|
@ -342,7 +355,7 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
where = "report_id = ?";
|
||||
String[] columns = {"tracker_id"};
|
||||
String order = "tracker_id DESC";
|
||||
cursor = db.query("trackers_reports",columns,where,whereArgs,null,null,order);
|
||||
cursor = db.query("trackers_reports", columns, where, whereArgs, null, null, order);
|
||||
//get trackersIds
|
||||
while (cursor.moveToNext()) {
|
||||
report.trackers.add(cursor.getLong(0));
|
||||
|
@ -355,9 +368,9 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
String[] columns = {"creator"};
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(applicationId)};
|
||||
Cursor cursor = getReadableDatabase().query("applications",columns,where,whereArgs,null,null,null);
|
||||
Cursor cursor = getReadableDatabase().query("applications", columns, where, whereArgs, null, null, null);
|
||||
String creator;
|
||||
if(cursor.moveToFirst())
|
||||
if (cursor.moveToFirst())
|
||||
creator = cursor.getString(0);
|
||||
else
|
||||
creator = "";
|
||||
|
@ -365,14 +378,40 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
return creator;
|
||||
}
|
||||
|
||||
|
||||
public List<Tracker> getTrackers() {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor cursor = db.query("trackers", null, null, null, null, null, null, null);
|
||||
List<Tracker> trackers = new ArrayList<>();
|
||||
if (cursor.getCount() == 0) {
|
||||
cursor.close();
|
||||
return null;
|
||||
}
|
||||
while (cursor.moveToNext()) {
|
||||
Tracker tracker = new Tracker();
|
||||
int col = 0;
|
||||
tracker.id = cursor.getLong(col++);
|
||||
tracker.name = cursor.getString(col++);
|
||||
long creation = cursor.getLong(col++);
|
||||
tracker.creationDate = Calendar.getInstance();
|
||||
tracker.creationDate.setTimeInMillis(creation);
|
||||
tracker.codeSignature = cursor.getString(col++);
|
||||
tracker.networkSignature = cursor.getString(col++);
|
||||
tracker.website = cursor.getString(col++);
|
||||
tracker.description = cursor.getString(col);
|
||||
trackers.add(tracker);
|
||||
}
|
||||
cursor.close();
|
||||
return trackers;
|
||||
}
|
||||
|
||||
public Tracker getTracker(long trackerId) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
String where = "id = ?";
|
||||
String[] whereArgs = {String.valueOf(trackerId)};
|
||||
Cursor cursor = db.query("trackers",null,where,whereArgs,null,null,null,null);
|
||||
Cursor cursor = db.query("trackers", null, where, whereArgs, null, null, null, null);
|
||||
Tracker tracker = null;
|
||||
if(cursor.moveToFirst())
|
||||
{
|
||||
if (cursor.moveToFirst()) {
|
||||
tracker = new Tracker();
|
||||
int col = 0;
|
||||
tracker.id = cursor.getLong(col++);
|
||||
|
@ -392,7 +431,7 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
|
||||
public Set<Tracker> getTrackers(Set<Long> trackers_id) {
|
||||
Set<Tracker> trackers = new HashSet<>();
|
||||
for(Long trackerId : trackers_id) {
|
||||
for (Long trackerId : trackers_id) {
|
||||
Tracker tracker = getTracker(trackerId);
|
||||
trackers.add(tracker);
|
||||
}
|
||||
|
@ -401,40 +440,39 @@ public class DatabaseManager extends SQLiteOpenHelper {
|
|||
|
||||
void insertOrUpdateTrackers(List<Tracker> trackersList) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
for(Tracker tracker : trackersList) {
|
||||
insertOrUpdateTracker(db,tracker);
|
||||
for (Tracker tracker : trackersList) {
|
||||
insertOrUpdateTracker(db, tracker);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String,String> getSources(String packageName) {
|
||||
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())
|
||||
{
|
||||
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) {
|
||||
private String buildSourcesStr(Map<String, String> sources) {
|
||||
StringBuilder sourceStr = new StringBuilder();
|
||||
for(Map.Entry<String,String> entry : sources.entrySet()) {
|
||||
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<>();
|
||||
Map<String, String> sources = new HashMap<>();
|
||||
String[] sourceList = sourcesStr.split("\\|");
|
||||
for(String sourceItem : sourceList){
|
||||
if(!sourceItem.isEmpty()) {
|
||||
for (String sourceItem : sourceList) {
|
||||
if (!sourceItem.isEmpty()) {
|
||||
String[] data = sourceItem.split(":");
|
||||
if(data.length == 2)
|
||||
if (data.length == 2)
|
||||
sources.put(data[0], data[1]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,17 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.manager;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.eu.exodus_privacy.exodusprivacy.R;
|
||||
import org.eu.exodus_privacy.exodusprivacy.Utils;
|
||||
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;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -32,30 +40,23 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
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;
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
/*
|
||||
Singleton that handle all network connection
|
||||
|
@ -74,34 +75,47 @@ public class NetworkManager {
|
|||
return instance;
|
||||
}
|
||||
|
||||
|
||||
public void getSingleReport(Context context, NetworkListener listener, String packageName) {
|
||||
Message mes = new Message();
|
||||
mes.type = Message_Type.GET_SINGLE_REPORT;
|
||||
mes.context = context;
|
||||
mes.listener = listener;
|
||||
mes.args = new Bundle();
|
||||
mes.args.putString("package", packageName);
|
||||
addMessageToQueue(mes);
|
||||
}
|
||||
|
||||
public void getReports(Context context, NetworkListener listener, ArrayList<String> packageList) {
|
||||
Message mes = new Message();
|
||||
mes.type = Message_Type.GET_REPORTS;
|
||||
mes.context = context;
|
||||
mes.listener = listener;
|
||||
mes.args = new Bundle();
|
||||
mes.args.putStringArrayList("packages",packageList);
|
||||
mes.args.putStringArrayList("packages", packageList);
|
||||
addMessageToQueue(mes);
|
||||
}
|
||||
|
||||
private void addMessageToQueue(Message mes) {
|
||||
if (thread == null || thread.getState() == Thread.State.TERMINATED || !thread.isRunning)
|
||||
thread = new NetworkProcessingThread();
|
||||
thread.queueMessage(mes);
|
||||
if (thread.getState() == Thread.State.NEW)
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private enum Message_Type {
|
||||
GET_REPORTS,
|
||||
GET_SINGLE_REPORT,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
private void addMessageToQueue(Message mes){
|
||||
if(thread == null || thread.getState() == Thread.State.TERMINATED || !thread.isRunning)
|
||||
thread = new NetworkProcessingThread();
|
||||
thread.queueMessage(mes);
|
||||
if(thread.getState() == Thread.State.NEW)
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private class NetworkProcessingThread extends Thread {
|
||||
private List<Message> messageQueue;
|
||||
private Semaphore sem;
|
||||
private static class NetworkProcessingThread extends Thread {
|
||||
private final String domain = Utils.getDomain();
|
||||
private final String apiUrl = "https://" + domain + "/api/";
|
||||
private final List<Message> messageQueue;
|
||||
private final Semaphore sem;
|
||||
boolean isRunning;
|
||||
private final String apiUrl = "https://reports.exodus-privacy.eu.org/api/";
|
||||
|
||||
NetworkProcessingThread() {
|
||||
messageQueue = new ArrayList<>();
|
||||
|
@ -116,14 +130,24 @@ public class NetworkManager {
|
|||
@Override
|
||||
public void run() {
|
||||
isRunning = true;
|
||||
Message mes;
|
||||
while (isRunning) {
|
||||
try {
|
||||
sem.acquire();
|
||||
Message mes = messageQueue.remove(0);
|
||||
mes = messageQueue.remove(0);
|
||||
switch (mes.type) {
|
||||
case GET_REPORTS:
|
||||
getTrackers(mes);
|
||||
getApplications(mes);
|
||||
SharedPreferences sharedPreferences = mes.context.getSharedPreferences(Utils.APP_PREFS, MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(Utils.LAST_REFRESH, Utils.dateToString(new Date()));
|
||||
editor.apply();
|
||||
break;
|
||||
case GET_SINGLE_REPORT:
|
||||
String packageName = mes.args.getString("package");
|
||||
Application application = getSingleReport(mes, packageName);
|
||||
mes.listener.onSuccess(application);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -135,6 +159,7 @@ public class NetworkManager {
|
|||
}
|
||||
|
||||
private JSONObject makeDataRequest(Context context, NetworkListener listener, URL url) {
|
||||
|
||||
if (!isConnectedToInternet(context)) {
|
||||
listener.onError(context.getString(R.string.not_connected));
|
||||
return null;
|
||||
|
@ -147,31 +172,32 @@ public class NetworkManager {
|
|||
urlConnection = (HttpURLConnection) url.openConnection();
|
||||
urlConnection.setRequestProperty("Content-Type", "application/json");
|
||||
urlConnection.setRequestProperty("Accept", "application/json");
|
||||
urlConnection.setRequestProperty("Authorization","Token "+context.getString(R.string.exodus));
|
||||
urlConnection.setRequestProperty("Authorization", "Token " + context.getString(R.string.exodus));
|
||||
urlConnection.setDoInput(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
inStream = urlConnection.getInputStream();
|
||||
} catch (Exception e) {
|
||||
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
inStream = urlConnection.getErrorStream();
|
||||
|
||||
}
|
||||
JSONObject object = null;
|
||||
if(success) {
|
||||
if (success) {
|
||||
String jsonStr = getJSON(inStream);
|
||||
try {
|
||||
object = new JSONObject(jsonStr);
|
||||
} catch (Exception e)
|
||||
{
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if(inStream != null)
|
||||
if (inStream != null)
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -181,33 +207,36 @@ public class NetworkManager {
|
|||
}
|
||||
|
||||
private void getTrackers(Message mes) {
|
||||
mes.listener.onProgress(R.string.get_trackers_connection,0,0);
|
||||
mes.listener.onProgress(R.string.get_trackers_connection, 0, 0);
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(apiUrl+"trackers");
|
||||
} catch (Exception e){
|
||||
url = new URL(apiUrl + "trackers");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
JSONObject object = makeDataRequest(mes.context,mes.listener,url);
|
||||
mes.listener.onProgress(R.string.get_trackers,0,0);
|
||||
JSONObject object = makeDataRequest(mes.context, mes.listener, url);
|
||||
mes.listener.onProgress(R.string.get_trackers, 0, 0);
|
||||
|
||||
if(object != null) {
|
||||
if (object != null) {
|
||||
try {
|
||||
JSONObject trackers = object.getJSONObject("trackers");
|
||||
List<Tracker> trackersList = new ArrayList<>();
|
||||
for(int i = 0; i<trackers.names().length(); i++) {
|
||||
mes.listener.onProgress(R.string.parse_trackers,i+1,trackers.names().length());
|
||||
String trackerId = trackers.names().get(i).toString();
|
||||
JSONObject tracker = trackers.getJSONObject(trackerId);
|
||||
Tracker track = parseTracker(tracker,trackerId);
|
||||
trackersList.add(track);
|
||||
if (trackersList.size() == 20) {
|
||||
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
||||
trackersList.clear();
|
||||
JSONArray trackerNames = trackers.names();
|
||||
if (trackerNames != null) {
|
||||
for (int i = 0; i < trackerNames.length(); i++) {
|
||||
mes.listener.onProgress(R.string.parse_trackers, i + 1, trackerNames.length());
|
||||
String trackerId = trackerNames.get(i).toString();
|
||||
JSONObject tracker = trackers.getJSONObject(trackerId);
|
||||
Tracker track = parseTracker(tracker, trackerId);
|
||||
trackersList.add(track);
|
||||
if (trackersList.size() == 20) {
|
||||
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
||||
trackersList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!trackersList.isEmpty())
|
||||
if (!trackersList.isEmpty())
|
||||
DatabaseManager.getInstance(mes.context).insertOrUpdateTrackers(trackersList);
|
||||
trackersList.clear();
|
||||
} catch (JSONException e) {
|
||||
|
@ -216,22 +245,22 @@ public class NetworkManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void getApplications(Message mes) {
|
||||
mes.listener.onProgress(R.string.get_reports_connection,0,0);
|
||||
mes.listener.onProgress(R.string.get_reports_connection, 0, 0);
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(apiUrl+"applications?option=short");
|
||||
} catch (Exception e){
|
||||
url = new URL(apiUrl + "applications?option=short");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
JSONObject object = makeDataRequest(mes.context,mes.listener,url);
|
||||
mes.listener.onProgress(R.string.get_reports,0,0);
|
||||
JSONObject object = makeDataRequest(mes.context, mes.listener, url);
|
||||
mes.listener.onProgress(R.string.get_reports, 0, 0);
|
||||
|
||||
|
||||
|
||||
if(object != null) {
|
||||
Map<String,Map<String,String>> handles = new HashMap<>();
|
||||
if (object != null) {
|
||||
Map<String, Map<String, String>> handles = new HashMap<>();
|
||||
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
||||
if (packages == null)
|
||||
return;
|
||||
|
@ -240,31 +269,31 @@ public class NetworkManager {
|
|||
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);
|
||||
String handle = app.getString("handle");
|
||||
String auid = app.getString("app_uid");
|
||||
String source = app.getString("source");
|
||||
Map<String,String> sources = handles.get(handle);
|
||||
if(sources == null)
|
||||
Map<String, String> sources = handles.get(handle);
|
||||
if (sources == null)
|
||||
sources = new HashMap<>();
|
||||
|
||||
sources.put(source,auid);
|
||||
sources.put(source, auid);
|
||||
if (packages.contains(handle))
|
||||
handles.put(handle,sources);
|
||||
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());
|
||||
SecureRandom rand = new SecureRandom();
|
||||
int alea = rand.nextInt(120) % 10 + 11;
|
||||
for(int i = 0 ; i < alea; i++) {
|
||||
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<>());
|
||||
handles.put(handle, new HashMap<>());
|
||||
packages.add(handle);
|
||||
}
|
||||
//shuffle the list
|
||||
|
@ -275,34 +304,33 @@ public class NetworkManager {
|
|||
e.printStackTrace();
|
||||
mes.listener.onError(mes.context.getString(R.string.json_error));
|
||||
}
|
||||
object = null;
|
||||
getReports(mes,handles,packages);
|
||||
getReports(mes, handles, packages);
|
||||
}
|
||||
mes.listener.onSuccess();
|
||||
mes.listener.onSuccess(null);
|
||||
}
|
||||
|
||||
private void getReports(Message mes, Map<String, Map<String,String>> handles, ArrayList<String> packages) {
|
||||
for(int i = 0; i < packages.size(); i++) {
|
||||
mes.listener.onProgress(R.string.parse_application,i+1,packages.size());
|
||||
getReport(mes,packages.get(i),handles.get(packages.get(i)));
|
||||
private void getReports(Message mes, Map<String, Map<String, String>> handles, ArrayList<String> packages) {
|
||||
for (int i = 0; i < packages.size(); i++) {
|
||||
mes.listener.onProgress(R.string.parse_application, i + 1, packages.size());
|
||||
getReport(mes, packages.get(i), handles.get(packages.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
private void getReport(Message mes, String handle, Map<String,String> sources) {
|
||||
private void getReport(Message mes, String handle, Map<String, String> sources) {
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(apiUrl+"search/"+handle);
|
||||
} catch (Exception e){
|
||||
url = new URL(apiUrl + "search/" + handle);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
JSONObject object = makeDataRequest(mes.context,mes.listener,url);
|
||||
JSONObject object = makeDataRequest(mes.context, mes.listener, url);
|
||||
|
||||
if(object != null) {
|
||||
if (object != null) {
|
||||
try {
|
||||
JSONObject application = object.getJSONObject(handle);
|
||||
ArrayList<String> packages = mes.args.getStringArrayList("packages");
|
||||
if(packages != null && packages.contains(handle)) {
|
||||
if (packages != null && packages.contains(handle)) {
|
||||
Application app = parseApplication(application, handle);
|
||||
app.sources = sources;
|
||||
DatabaseManager.getInstance(mes.context).insertOrUpdateApplication(app);
|
||||
|
@ -313,6 +341,29 @@ public class NetworkManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private Application getSingleReport(Message mes, String handle) {
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(apiUrl + "search/" + handle);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
JSONObject object = makeDataRequest(mes.context, mes.listener, url);
|
||||
if (object != null) {
|
||||
try {
|
||||
if (handle != null) {
|
||||
JSONObject application = object.getJSONObject(handle);
|
||||
return parseApplication(application, handle);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
mes.listener.onError(mes.context.getString(R.string.json_error));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Application parseApplication(JSONObject object, String packageName) throws JSONException {
|
||||
Application application = new Application();
|
||||
application.packageName = packageName;
|
||||
|
@ -322,7 +373,7 @@ public class NetworkManager {
|
|||
//parse Report
|
||||
application.reports = new HashSet<>();
|
||||
JSONArray reports = object.getJSONArray("reports");
|
||||
for(int i = 0; i < reports.length(); i++) {
|
||||
for (int i = 0; i < reports.length(); i++) {
|
||||
Report report = parseReport(reports.getJSONObject(i));
|
||||
application.reports.add(report);
|
||||
}
|
||||
|
@ -335,25 +386,32 @@ public class NetworkManager {
|
|||
report.downloads = object.getString("downloads");
|
||||
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"));
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
|
||||
try {
|
||||
report.updateDate = Calendar.getInstance();
|
||||
report.updateDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
report.updateDate.setTime(dateFormat.parse(object.getString("updated_at")));
|
||||
report.updateDate.set(Calendar.MILLISECOND,0);
|
||||
Date date = dateFormat.parse(object.getString("updated_at"));
|
||||
if (date != null) {
|
||||
report.updateDate.setTime(date);
|
||||
}
|
||||
report.updateDate.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
report.creationDate = Calendar.getInstance();
|
||||
report.creationDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
report.creationDate.setTime(dateFormat.parse(object.getString("creation_date")));
|
||||
report.creationDate.set(Calendar.MILLISECOND,0);
|
||||
report.creationDate.setTime(date!=null?date:new Date());
|
||||
date = dateFormat.parse(object.getString("creation_date"));
|
||||
if (date != null) {
|
||||
report.creationDate.setTime(date);
|
||||
}
|
||||
report.creationDate.set(Calendar.MILLISECOND, 0);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
JSONArray trackersArray = object.getJSONArray("trackers");
|
||||
report.trackers = new HashSet<>();
|
||||
for(int i = 0; i < trackersArray.length(); i++)
|
||||
for (int i = 0; i < trackersArray.length(); i++)
|
||||
report.trackers.add(trackersArray.getLong(i));
|
||||
return report;
|
||||
}
|
||||
|
@ -370,7 +428,10 @@ public class NetworkManager {
|
|||
try {
|
||||
tracker.creationDate = Calendar.getInstance();
|
||||
tracker.creationDate.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
tracker.creationDate.setTime(dateFormat.parse(object.getString("creation_date")));
|
||||
Date date = dateFormat.parse(object.getString("creation_date"));
|
||||
if (date != null) {
|
||||
tracker.creationDate.setTime(date);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -402,23 +463,22 @@ public class NetworkManager {
|
|||
private boolean isConnectedToInternet(Context context) {
|
||||
//verify the connectivity
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if(connectivityManager == null)
|
||||
if (connectivityManager == null)
|
||||
return false;
|
||||
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
if (networkInfo != null) {
|
||||
NetworkInfo.State networkState = networkInfo.getState();
|
||||
if (networkState.equals(NetworkInfo.State.CONNECTED)) {
|
||||
return true;
|
||||
}
|
||||
return networkState.equals(NetworkInfo.State.CONNECTED);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class Message{
|
||||
private static class Message {
|
||||
Message_Type type = Message_Type.UNKNOWN;
|
||||
Bundle args = new Bundle();
|
||||
NetworkListener listener;
|
||||
Context context;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class Application {
|
||||
|
@ -28,7 +27,7 @@ public class Application {
|
|||
public String name;
|
||||
public String creator;
|
||||
public Set<Report> reports;
|
||||
public Map<String,String> sources;
|
||||
public Map<String, String> sources;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.eu.exodus_privacy.exodusprivacy.objects;
|
||||
|
||||
public class MyTracker {
|
||||
|
||||
public String signature;
|
||||
public Tracker tracker;
|
||||
public int number;
|
||||
}
|
|
@ -7,7 +7,6 @@ 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;
|
||||
|
@ -31,7 +30,7 @@ public class ReportDisplay {
|
|||
public String viewOnStore;
|
||||
|
||||
|
||||
private ReportDisplay(){
|
||||
private ReportDisplay() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -43,32 +42,32 @@ public class ReportDisplay {
|
|||
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.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);
|
||||
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++) {
|
||||
List<Permission> requestedPermissions = new ArrayList<>();
|
||||
if (info != null && manager != null && 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)
|
||||
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)
|
||||
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
|
||||
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)
|
||||
if (permissionGroupInfo.loadIcon(manager) != null)
|
||||
permission.icon = permissionGroupInfo.loadIcon(manager);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromYDelta="0%"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:toYDelta="100%" />
|
||||
</set>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromYDelta="100%"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:toYDelta="0%" />
|
||||
</set>
|
|
@ -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="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z" />
|
||||
</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>
|
|
@ -34,10 +34,9 @@
|
|||
<shape>
|
||||
<corners android:radius="5dip" />
|
||||
<gradient
|
||||
android:startColor="#FF684971"
|
||||
android:endColor="#FF3d2b43"
|
||||
android:angle="270"
|
||||
/>
|
||||
android:endColor="@color/colorAccent"
|
||||
android:startColor="@color/colorAccent"
|
||||
android:angle="270" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
<?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>
|
||||
|
||||
<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_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="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@{reportInfo.name}"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/colorPurple"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/dummy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="15dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trackers_nb"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:background="@{ContextCompat.getDrawable(context,reportInfo.trackerColor)}"
|
||||
android:text="@{reportInfo.trackerNumberStr}"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/textColorWhite"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dummy" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/trackers_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/trackers"
|
||||
android:textColor="@color/textColorDark"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/trackers_nb"
|
||||
app:layout_constraintTop_toTopOf="@id/trackers_nb" />
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/installed_version"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/report_version"
|
||||
android:textColor="@color/textColorDark"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/trackers_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/installed_version_value"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:text="@{reportInfo.installedVersion}"
|
||||
android:textColor="@color/textColorDark"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/installed_version"
|
||||
app:layout_constraintTop_toTopOf="@+id/installed_version" />
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_date"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:textColor="@color/textColorDarkLight"
|
||||
android:textSize="16sp"
|
||||
android:visibility="@{reportInfo.reportVisibility ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/installed_version_value" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_url"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:autoLink="web"
|
||||
android:text="@string/view_on_exodus"
|
||||
android:textAlignment="textEnd"
|
||||
android:textColor="@color/colorPurple"
|
||||
android:textSize="16sp"
|
||||
android:visibility="@{reportInfo.reportVisibility ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/report_date" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/report_url">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/trackers"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/analysed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/analysed"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:visibility="@{reportInfo.trackerVisibility ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/report_url" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</layout>
|
|
@ -63,7 +63,7 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:src="@drawable/ic_logo_purple"
|
||||
android:src="@drawable/ic_logo"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp" />
|
||||
<ProgressBar
|
||||
|
|
|
@ -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">
|
||||
|
||||
|
@ -262,7 +263,7 @@
|
|||
android:text="@{reportInfo.trackerNumberStr}"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/analysed"
|
||||
app:layout_constraintTop_toBottomOf="@id/analyse_app"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:background="@{ContextCompat.getDrawable(context,reportInfo.trackerColor)}"
|
||||
android:visibility="@{reportInfo.trackerVisibility ? View.VISIBLE : View.GONE}"
|
||||
|
@ -281,7 +282,7 @@
|
|||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/analysed"
|
||||
app:layout_constraintTop_toBottomOf="@id/analyse_app"
|
||||
app:layout_constraintStart_toEndOf="@id/trackers_nb_list"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:textStyle="bold"
|
||||
|
@ -436,9 +437,21 @@
|
|||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
/>
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/analyse_app"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/analyse_app"
|
||||
android:visibility="@{reportInfo.trackerVisibility ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/analysed" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</layout>
|
|
@ -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>
|
|
@ -5,8 +5,13 @@
|
|||
android:id="@+id/action_filter"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/menu_action_filter"
|
||||
app:actionViewClass="android.widget.SearchView"
|
||||
app:showAsAction="ifRoom|collapseActionView" />
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="always|collapseActionView" />
|
||||
<item
|
||||
android:id="@+id/action_filter_options"
|
||||
android:icon="@drawable/ic_baseline_filter_list_24"
|
||||
android:title="@string/menu_action_filter"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group
|
||||
android:id="@+id/filter_by_name_grp"
|
||||
android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/filter_by_name"
|
||||
android:title="@string/filter_by_name" />
|
||||
<item
|
||||
android:id="@+id/having_less_trackers"
|
||||
android:title="@string/having_less_trackers" />
|
||||
<item
|
||||
android:id="@+id/having_most_trackers"
|
||||
android:title="@string/having_most_trackers" />
|
||||
<item
|
||||
android:id="@+id/having_less_permissions"
|
||||
android:title="@string/having_less_permissions" />
|
||||
<item
|
||||
android:id="@+id/having_most_permissions"
|
||||
android:title="@string/having_most_permissions" />
|
||||
</group>
|
||||
</menu>
|
|
@ -1,11 +0,0 @@
|
|||
<?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>
|