Skip to content

Commit

Permalink
Add support to Android 13 (#276)
Browse files Browse the repository at this point in the history
* Update to API 33

* Improve config build

* Add new permission and enable locales config

* Add themed icon

* Fix format

* Fix resConfig

* Bump dependencies

* Api 33 (#273)

* Update Github actions to remove network config (#269)

* Issue 260 (#270)

* Update Github actions to remove network config (#269)

* Add sequence diagram of PackageManagerModule

* Move calls to PackageManager outside of nested loop

We do not call the PackageManager from inside a nested for loop anymore.
Instead the generation of the Permission instances list was lifted out.
Also the number of times we do callbacks to the packageManager is
reduced. This should reduce the occurrence of Issue #260 and Issue #264.

* Calculate short name on view time

* Add test for identity

* Linting

* Rewrite test for more accuracy

* Avoid regex

* Readd sorting of permissions list

* Refactor to repository pattern

* Update tests accordingly

* Linting

* Fix typo

* Refactor Permission Data Class

Now uses longName for identification and short name for display.

* Correct sorting of permissions

* Fix name computing

---------

Co-authored-by: Jean-Baptiste <87148630+Jean-BaptisteC@users.noreply.github.com>

* Update to API 33

* Improve config build

* Add new permission and enable locales config

* Add themed icon

* Fix format

* Fix resConfig

* Bump dependencies

* Add sequence diagram

* WIP Implement logic to store notification permission info

* WIP Use notification permission info in VM

* WIP Implementing the permission request logic

* WIP Implement permission request

* Implement onRequestPermissionsResult

* Use single key for saving perm info

* Use single key for saving perm info

* Check for permission before showing notification

* Refactor request and check to own funcs

* Add logging

* Add ToDo

* Move the DataStoreModule

* Add A DataStoreRepo and a Storage Interface

* Adapt DataStoreModule

* Refactor for new architecture

* Remove dataStoreModule from Service

* Collect only the first elem

* Cache config

* Inject networkManager in constructor

* Reorder functions

* Load config as LiveData

* Move init to DialogFragment

* Use MainActivityViewModel, implement init

DialogFragment VM is currently redundant as it would again use
identical functionality when saving app data. Also due to init happening
in the Fragment now, we need to access functionality from the MAVM.

* Don't use flow in insert

* Add logging

* Start only when permission was asked

* Save appAppSetup state

* Make compatible with lower API levels

* Refactor to exodus names

* Implement tests for DataStoreRepo

* Make DSModule Object, implement data class for name

* Linting

* Remove unused var

* Remove redundant view model

* Check for network connection on startup

* Implement explicit saving of app setup status

* Save app setup status when done

* Only ask permission on API Level 33 and up

* Remove saving app setup status

* Catch case where no wifi settings are available

* Add refresh snackbar when applist is empty

* Add refresh snackbar to TrackersFragment as well

* Test for correct insertion of app setup state

* Make new datastores for each test

* Add swipeRefreshLayout when list is null to allow refresh

* Remove Snackbar

As the swipeRefreshLayout is visible, a button might not be needed.

* Remove redundant method calls

* Remove unused function

* Linting

* Fix broken test

* Create notification channel unconditionally

According to https://developer.android.com/develop/ui/views/notifications/channels#CreateChannel
No operation will be performed, when the channel already exists.

* Remove unused import

* Remove foreground service specific method

* Update onDestroy

* Split notification build and setup

* Add timeout to notification

* Refactor stopService

* Linting

---------

Co-authored-by: Jean-Baptiste <87148630+Jean-BaptisteC@users.noreply.github.com>
Co-authored-by: Jean-Baptiste CHARRON <jeanbaptiste.charron@outlook.fr>

* Bump dependencies

* Lint

* Bump com.google.dagget.hilt to 2.46.1

* Migrate to non-transitiveRClass

* Bump androidx.room to 2.5.1

* Api 33 (#277)

* Bump coroutines to 1.7.1

* Fix apr repo test
* Cleanup of opt ins to experimental test coroutines

* Clean up

* Remove unsused extension fun
* Remove opt ins

* Expand test coverage

* Add an additional test for retrieving a list of trackers
* Remove opt ins
* Improve format

* Clean up

* Remove unused test rules
* Remove opt ins

* Clean Up

* Remove opt ins
* Remove unused vals

* Bump kotlinx:kotlinx-coroutines-test to 1.7.1

* Bump com.google.android.material to 1.9.0

Fixes broken sub fragments.

* Update Compile options for kotlin

* Bump gradle to 8.0.1

* Update operators

* Remove redundant test

* Bump JDK version (#280)

* Fix deprecations (#281)

* Implement extension fun for getting pkgs

* Implement extension fun for app source

* Move getInstalledPackagesList to common

Implement getSource in common

* Import extension funs in PackageRepository

* Adapt PackageRepositoryTest

* cleanup
* use extension fun
* fix deprecations

* Linting

* remove unnecessary comment

* Fix crash when device has not mail app or app store

* Api 33 (#291)

* Set white chip icon color in dark mode

* Use themed text and icon colors in chip

@color/m3_chip_text_color was marked private in material 1.9.0.
So a default color was used, which broke the style of the chip.
Add light/dark theme specific colors for chip text color and icon.

---------

Co-authored-by: PatDyn <37243484+PatDyn@users.noreply.github.com>
  • Loading branch information
Jean-BaptisteC and PatDyn authored May 25, 2023
1 parent 0acb338 commit 698d3a0
Show file tree
Hide file tree
Showing 39 changed files with 724 additions and 434 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17
- name: Run Kotlin Linter
run: ./gradlew app:ktlintCheck --info
- name: Generate debug build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v1
with:
java-version: 11
java-version: 17
- name: Decode Keystore
run: |
echo "${{secrets.RELEASE_KEYSTORE}}" > release.keystore.asc
Expand Down
68 changes: 36 additions & 32 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ plugins {
}

android {
compileSdk 32
compileSdk 33

defaultConfig {
minSdk 21
targetSdk 32
targetSdk 33
versionCode 14
versionName "3.0.1"
testInstrumentationRunner 'org.eu.exodus_privacy.exodusprivacy.ExodusTestRunner'
Expand All @@ -25,6 +25,7 @@ android {
)
}
}
resourceConfigurations += ['en', 'ar', 'ca', 'de', 'el', 'fr', 'it', 'pt_BR', 'ru', 'tr', 'uk']
}
signingConfigs {
releaseConfig {
Expand All @@ -44,6 +45,10 @@ android {
}
}
buildTypes {
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-debug'
}
release {
minifyEnabled true
shrinkResources true
Expand All @@ -55,8 +60,11 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
testOptions {
unitTests {
Expand All @@ -67,9 +75,6 @@ android {
// Adds exported schema location as test app assets.
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
viewBinding true
}
Expand All @@ -88,25 +93,24 @@ dependencies {
// r8
implementation 'com.android.tools:r8:8.0.40'

implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.core:core-ktx:1.10.1'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'io.noties.markwon:core:4.6.2'
implementation 'androidx.window:window:1.0.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.appcompat:appcompat:1.6.1'

implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
//Don't update android material to version 1.7.0, this version broken permission sub fragment
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.browser:browser:1.5.0'
implementation 'androidx.datastore:datastore-preferences:1.0.0'
implementation 'com.facebook.shimmer:shimmer:0.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation 'androidx.test.ext:junit-ktx:1.1.5'

// Navigation Components
Expand All @@ -120,52 +124,52 @@ dependencies {
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

// okhttp
def okhttp_version = '4.10.0'
def okhttp_version = '4.11.0'
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"

// Hilt
def hilt_version = '2.45'
def hilt_version = '2.46.1'
kapt "com.google.dagger:hilt-compiler:$hilt_version"
implementation "com.google.dagger:hilt-android:$hilt_version"

// Lifecycle
def lifecycle_version = '2.5.1'
def lifecycle_version = '2.6.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

// Room
def room_version = '2.4.3'
def room_version = '2.5.1'
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-runtime:$room_version"

// KTX
implementation 'androidx.fragment:fragment-ktx:1.5.4'
implementation 'androidx.activity:activity-ktx:1.5.1'
implementation 'androidx.fragment:fragment-ktx:1.5.7'
implementation 'androidx.activity:activity-ktx:1.7.1'

// unit tests
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.9'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"
testImplementation 'org.robolectric:robolectric:4.10.2'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1"
testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.test:runner:1.5.2"
testImplementation "androidx.test:rules:1.5.0"
testImplementation 'com.google.dagger:hilt-android-testing:2.45'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
kaptTest 'com.google.dagger:hilt-compiler:2.45'
testImplementation 'com.google.dagger:hilt-android-testing:2.46.1'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
kaptTest 'com.google.dagger:hilt-compiler:2.46.1'

// instrumentation tests
kaptAndroidTest 'com.google.dagger:hilt-compiler:2.45'
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.45'
kaptAndroidTest 'com.google.dagger:hilt-compiler:2.46.1'
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.46.1'
androidTestImplementation "androidx.test:core:1.5.0"
androidTestImplementation "androidx.test:core-ktx:1.5.0"
androidTestImplementation "androidx.test:runner:1.5.2"
androidTestImplementation "androidx.test:rules:1.5.0"
androidTestImplementation "androidx.room:room-testing:2.4.1"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4"
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation "androidx.room:room-testing:2.5.1"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1"
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
}

class RoomSchemaArgProvider implements CommandLineArgumentProvider {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package org.eu.exodus_privacy.exodusprivacy

import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ServiceTestRule
import dagger.Module
import dagger.Provides
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.runTest
import okhttp3.Interceptor
Expand All @@ -29,6 +27,7 @@ import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.seconds

const val FAKE_PATH = "/api/requests/"
const val FAKE_PORT = 34567
Expand Down Expand Up @@ -93,12 +92,8 @@ class ExodusAPIRepositoryTest {
@get:Rule
val hiltRule = HiltAndroidRule(this)

@get:Rule
val serviceRule = ServiceTestRule()

private val mockWebServer = MockWebServer()
private val socketPolicy = SocketPolicy.NO_RESPONSE
@OptIn(ExperimentalCoroutinesApi::class)
private val testDispatcher = StandardTestDispatcher()

@Inject
Expand All @@ -117,9 +112,8 @@ class ExodusAPIRepositoryTest {
mockWebServer.shutdown()
}

@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun exodusAPIRepositoryShouldTimeOut() = runTest(testDispatcher) {
fun exodusAPIRepositoryShouldTimeOut() = runTest(testDispatcher, timeout = 12.seconds) {
// given
hiltRule.inject()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.eu.exodus_privacy.exodusprivacy

import android.content.Context
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.eu.exodus_privacy.exodusprivacy.manager.storage.DataStoreName
import org.eu.exodus_privacy.exodusprivacy.manager.storage.ExodusConfig
import org.eu.exodus_privacy.exodusprivacy.manager.storage.ExodusDataStoreRepository
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@HiltAndroidTest
class ExodusDataStoreRepositoryTest {
@get:Rule
val hiltRule = HiltAndroidRule(this)

private lateinit var context: Context
private lateinit var dataStoreRepository: ExodusDataStoreRepository<ExodusConfig>

@Before
fun setup() {
context = getInstrumentation().targetContext
}

@Test
fun testReturnsDefaults() = runTest {
// given
dataStoreRepository = ExodusDataStoreRepository(
Gson(),
stringPreferencesKey("testKey"),
object : TypeToken<Map<String, ExodusConfig>>() {},
DataStoreName("testDataStore1"),
context
)

// when
val defaults = dataStoreRepository.getAll().first()

// then
assert(defaults.containsValue(ExodusConfig("privacy_policy_consent", false)))
assert(defaults.containsValue(ExodusConfig("is_setup_complete", false)))
assert(defaults.containsValue(ExodusConfig("notification_requested", false)))
}

@Test
fun testInsertsAndRetrievesCorrectVal() = runTest {
// given
dataStoreRepository = ExodusDataStoreRepository(
Gson(),
stringPreferencesKey("testKey"),
object : TypeToken<Map<String, ExodusConfig>>() {},
DataStoreName("testDataStore2"),
context
)

val newValues = mapOf(
"privacy_policy" to ExodusConfig("privacy_policy_consent", true),
"app_setup" to ExodusConfig("is_setup_complete", true),
"notification_perm" to ExodusConfig("notification_requested", true)
)

// when
dataStoreRepository.insert(newValues)
val values = dataStoreRepository.getAll().first()

// then
assert(values.containsValue(ExodusConfig("privacy_policy_consent", true)))
assert(values.containsValue(ExodusConfig("is_setup_complete", true)))
assert(values.containsValue(ExodusConfig("notification_requested", true)))
}

@Test
fun testInsertsAppSetupCorrectly() = runTest {
// given
dataStoreRepository = ExodusDataStoreRepository(
Gson(),
stringPreferencesKey("testKey"),
object : TypeToken<Map<String, ExodusConfig>>() {},
DataStoreName("testDataStore3"),
context
)

val values = mapOf(
"privacy_policy" to ExodusConfig("privacy_policy_consent", true),
"app_setup" to ExodusConfig("is_setup_complete", true),
"notification_perm" to ExodusConfig("notification_requested", true)
)

// when
dataStoreRepository.insert(values)
dataStoreRepository.insertAppSetup(ExodusConfig("is_setup_complete", false))
val appSetup = dataStoreRepository.get("app_setup").first()

// then
assert(appSetup == ExodusConfig("is_setup_complete", false))
}
}
Loading

0 comments on commit 698d3a0

Please sign in to comment.