Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC] Implemented Notification Datastore and Work Manager #12234

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AnkiDroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
implementation 'com.github.ByteHamster:SearchPreference:v2.3.0'
implementation 'com.github.AppIntro:AppIntro:6.2.0'
implementation "androidx.work:work-runtime-ktx:2.7.1"
implementation "androidx.datastore:datastore-preferences:1.0.0"

// Cannot use debugImplementation since classes need to be imported in AnkiDroidApp
// and there's no no-op version for release build. Usage has been disabled for release
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.ichi2.anki

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.ichi2.anki.model.DeckNotification
import kotlinx.coroutines.runBlocking
import org.intellij.lang.annotations.Language
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.random.Random
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue

@RunWith(AndroidJUnit4::class)
class NotificationDatastoreTest {
private lateinit var notificationDatastore: NotificationDatastore

@Before
fun setup() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
notificationDatastore = NotificationDatastore.getInstance(context)
}

@Test
fun deckSchedDataReadWriteTest() {
val deckNotification = DeckNotification()

runBlocking {
val isSuccess = notificationDatastore.setDeckSchedData(
deckNotification.did,
deckNotification
)
assertTrue(
isSuccess,
"Unable to save the deck data in notification preference datastore."
)

val dataStored = notificationDatastore.getDeckSchedData(deckNotification.did)
assertNotNull(
dataStored,
"Unable to read the stored deck data from notification preference datastore."
)
}
}

@Test
fun unStoredDeckSchedDataTest() {
runBlocking {
val deckIdUnStored = Random.nextLong()
val dataUnStored = notificationDatastore.getDeckSchedData(deckIdUnStored)
assertNull(dataUnStored, "Expected null, But found data for deckId $deckIdUnStored")
}
}

@Test(expected = Exception::class)
fun deckSchedDataDeSerializationTest() {
val deckId = 2L

@Language("JSON")
val invalidDeckSchedJson = """
{
"deckPreference":{
"number":10,
"valueType":"CARDS"
},
"did":1,
"enabled":false,
"includeSubdecks":true,
"notificationTime": 0
}
""".trimIndent()

runBlocking {
notificationDatastore.putStringAsync(deckId.toString(), invalidDeckSchedJson)
notificationDatastore.getDeckSchedData(deckId)
}
}

@After
fun cleanUp() {
runBlocking {
notificationDatastore.clearDatastore()
}
}
}
12 changes: 12 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,18 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

<!-- Using custom work manager initialization SEE: https://issuetracker.google.com/issues/138465476 -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>

</manifest>
11 changes: 10 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import java.util.regex.Pattern
*/
@KotlinCleanup("lots to do")
@KotlinCleanup("IDE Lint")
open class AnkiDroidApp : Application() {
open class AnkiDroidApp : Application(), androidx.work.Configuration.Provider {
/** An exception if the WebView subsystem fails to load */
private var mWebViewError: Throwable? = null
private val mNotifications = MutableLiveData<Void?>()
Expand Down Expand Up @@ -182,9 +182,11 @@ open class AnkiDroidApp : Application() {
}
}
}
// TODO: Notification CleanUP. Delete the Boot Service after successful implementation of Notification Work Manager.
Timber.i("AnkiDroidApp: Starting Services")
BootService().onReceive(this, Intent(this, BootService::class.java))

// TODO: Notification CleanUP. Delete the Notification Service after successful implementation of Notification Work Manager.
// Register for notifications
mNotifications.observeForever { NotificationService.triggerNotificationFor(this) }
Themes.systemIsInNightMode =
Expand Down Expand Up @@ -212,6 +214,13 @@ open class AnkiDroidApp : Application() {
}
}

/**
* Our configuration for custom work manager.
* We are using custom work manager because UNIT TESTS are failing.
* TODO: Remove custom implementation after implementing 14 tests using WorkManagerTestInitHelper. SEE: https://developer.android.com/topic/libraries/architecture/workmanager/how-to/integration-testing
*/
override fun getWorkManagerConfiguration() = androidx.work.Configuration.Builder().build()

/**
* A tree which logs necessary data for crash reporting.
*
Expand Down
Loading