From c32f6e92828161e019c8f96684b82635397e1ab3 Mon Sep 17 00:00:00 2001
From: Prateek Singh <76490368+prateek-singh-3212@users.noreply.github.com>
Date: Fri, 3 Jun 2022 03:01:48 +0530
Subject: [PATCH] Implemented Work Manager
---
AnkiDroid/build.gradle | 3 +
AnkiDroid/src/main/AndroidManifest.xml | 5 -
.../java/com/ichi2/anki/AnkiDroidApp.java | 26 ++++
.../com/ichi2/anki/DeckMetaDataPreference.kt | 24 +++-
.../main/java/com/ichi2/anki/IntentHandler.kt | 12 --
.../anki/services/DeckMetaDataService.kt | 135 ------------------
.../ichi2/anki/worker/DeckMetaDataWorker.kt | 92 ++++++++++++
7 files changed, 141 insertions(+), 156 deletions(-)
delete mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt
create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/worker/DeckMetaDataWorker.kt
diff --git a/AnkiDroid/build.gradle b/AnkiDroid/build.gradle
index 0e670e535f44..b67e1c688906 100644
--- a/AnkiDroid/build.gradle
+++ b/AnkiDroid/build.gradle
@@ -331,5 +331,8 @@ dependencies {
// GSON
implementation 'com.google.code.gson:gson:2.9.0'
+
+ // Work Manager
+ implementation "androidx.work:work-runtime-ktx:2.7.1"
}
apply from: "./kotlinMigration.gradle"
diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml
index 62377325650b..b9a802893408 100644
--- a/AnkiDroid/src/main/AndroidManifest.xml
+++ b/AnkiDroid/src/main/AndroidManifest.xml
@@ -377,11 +377,6 @@
-
-
+ *
+ * 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, see .
+ */
+
package com.ichi2.anki
import android.content.Context
import android.content.SharedPreferences
import com.google.gson.Gson
-import com.ichi2.anki.services.DeckMetaDataService
+import com.ichi2.anki.worker.DeckMetaDataWorker
import timber.log.Timber
class DeckMetaDataPreference(context: Context) {
@@ -21,7 +37,7 @@ class DeckMetaDataPreference(context: Context) {
return sharedPreferences.getString(key, default)!!
}
- fun setMetaData(key: String, value: DeckMetaDataService.Meta) {
+ fun setMetaData(key: String, value: DeckMetaDataWorker.Meta) {
val json: String = Gson().toJson(value)
sharedPreferences.edit()
.putString(key, json)
@@ -29,14 +45,14 @@ class DeckMetaDataPreference(context: Context) {
Timber.tag("META").e(json)
}
- fun getMetaData(key: String): DeckMetaDataService.Meta? {
+ fun getMetaData(key: String): DeckMetaDataWorker.Meta? {
val jsonData = sharedPreferences
.getString(key, null)
return if (jsonData == null) {
null
} else {
- Gson().fromJson(jsonData, DeckMetaDataService.Meta::class.java)
+ Gson().fromJson(jsonData, DeckMetaDataWorker.Meta::class.java)
}
}
}
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt b/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt
index f316a2efb320..9c1ddf7e78bd 100644
--- a/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt
@@ -27,7 +27,6 @@ import com.ichi2.anki.UIUtils.showThemedToast
import com.ichi2.anki.dialogs.DialogHandler
import com.ichi2.anki.dialogs.DialogHandler.Companion.storeMessage
import com.ichi2.anki.servicelayer.ScopedStorageService
-import com.ichi2.anki.services.DeckMetaDataService
import com.ichi2.anki.services.ReminderService
import com.ichi2.themes.Themes.disableXiaomiForceDarkMode
import com.ichi2.utils.ImportUtils.handleFileImport
@@ -49,7 +48,6 @@ class IntentHandler : Activity() {
Timber.d("onCreate()")
super.onCreate(savedInstanceState)
disableXiaomiForceDarkMode(this)
- launchDeckMetaDataService()
setContentView(R.layout.progress_bar)
val intent = intent
Timber.v(intent.toString())
@@ -138,16 +136,6 @@ class IntentHandler : Activity() {
finish()
}
- private fun launchDeckMetaDataService() {
- Timber.tag("META").e("Launching deck meta data service...")
- val intent = Intent(this, DeckMetaDataService::class.java)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- startForegroundService(intent)
- } else {
- startService(intent)
- }
- }
-
// COULD_BE_BETTER: Also extract the parameters into here to reduce coupling
@VisibleForTesting
enum class LaunchType {
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt b/AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt
deleted file mode 100644
index fbf7717a3a9a..000000000000
--- a/AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.ichi2.anki.services
-
-import android.annotation.SuppressLint
-import android.app.AlarmManager
-import android.app.Notification
-import android.app.PendingIntent
-import android.app.Service
-import android.content.Intent
-import android.os.IBinder
-import androidx.core.app.NotificationCompat
-import com.ichi2.anki.CollectionHelper
-import com.ichi2.anki.DeckMetaDataPreference
-import com.ichi2.anki.NotificationChannels
-import com.ichi2.anki.R
-import com.ichi2.libanki.sched.Counts
-import com.ichi2.libanki.utils.Time
-import timber.log.Timber
-
-/**
- * This Service is responsible to Collect all the metadata and store it in share preference.
- * Technically it refreshes the Deck Meta Data. Whenever this service is called
- * then I will collect the new data of decks.
- * */
-class DeckMetaDataService : Service() {
-
- private lateinit var colHelper: CollectionHelper
-
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
-
- Timber.tag("META").e("On Service start command...")
-
- colHelper = CollectionHelper.getInstance()
-
- /**
- * It sets the notification till the service is completed.
- * */
- val notification = NotificationCompat.Builder(this, NotificationChannels.getId(NotificationChannels.Channel.GENERAL))
- .setOngoing(true)
- .setContentTitle("Anki")
- .setContentText("Ankidroid is syncing deck data.")
- .setSmallIcon(R.mipmap.ic_launcher)
- .setPriority(NotificationCompat.PRIORITY_LOW)
- .setSilent(true)
- .setCategory(Notification.CATEGORY_SERVICE)
- .build()
-
- startForeground(FOREGROUND_SERVICE_ID, notification)
-
- // Update the data of Deck Metadata from HERE
- val col = colHelper.getCol(this)
- val deckList = col.sched.deckDueList()
-
- deckList.forEach {
- val new = it?.newCount ?: -1
- val lrn = it?.lrnCount ?: -1
- val rev = it?.revCount ?: -1
- val data = Meta(
- it?.did ?: -1,
- it?.fullDeckName ?: "Deck Name",
- new,
- lrn,
- rev,
- col.sched.eta(Counts(new, lrn, rev), false)
- )
- storeInPreference(data)
- }
-
- updateLastFetch(colHelper.getTimeSafe(this).toString())
-
- stopSelf() // Stops the current running service.
- return START_NOT_STICKY
- }
-
- private fun updateLastFetch(time: String) {
- val metaPreference = DeckMetaDataPreference(this)
- metaPreference.putString(LAST_FETCH_TIME, time)
- }
-
- /**
- * It is used to store the data in the DeckMetaData Shared Preference.
- * */
- private fun storeInPreference(list: Meta) {
- val metaPreference = DeckMetaDataPreference(this)
- metaPreference.setMetaData(list.did.toString(), list)
- }
-
- /**
- * Does Nothing
- * */
- override fun onBind(intent: Intent?): IBinder? {
- // Kept Intentionally
- return null
- }
-
- override fun onDestroy() {
- Timber.tag("META").e("Deck meta data Service on Destroy...")
- scheduleNextAlarm(Long.MAX_VALUE) // Temp
- }
-
- /**
- * It is used to schedule the next alarm which helps in starting this service again.
- **/
- @SuppressLint("UnspecifiedImmutableFlag")
- private fun scheduleNextAlarm(interval: Long) {
- val time = colHelper.getTimeSafe(this).intTimeMS() + interval
-
- val intent = Intent(this, DeckMetaDataService::class.java)
- val pendingIntent = PendingIntent.getService(
- this.applicationContext, SERVICE_PENDING_INTENT_ID, intent, 0
- )
-
- val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
- alarmManager.set(
- AlarmManager.RTC_WAKEUP,
- time,
- pendingIntent
- )
- Timber.tag("META").e("Service will start again at %s", (Time.calendar(time).time))
- }
-
- data class Meta(
- val did: Long,
- val deckName: String,
- val new: Int,
- val lrn: Int,
- val rev: Int,
- val eta: Int
- )
-
- companion object {
- const val FOREGROUND_SERVICE_ID = 10001
- const val SERVICE_PENDING_INTENT_ID = 10002
- const val LAST_FETCH_TIME = "LAST_FETCH"
- }
-}
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/worker/DeckMetaDataWorker.kt b/AnkiDroid/src/main/java/com/ichi2/anki/worker/DeckMetaDataWorker.kt
new file mode 100644
index 000000000000..fb4a53bca815
--- /dev/null
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/worker/DeckMetaDataWorker.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2022 Prateek Singh
+ *
+ * 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, see .
+ */
+
+package com.ichi2.anki.worker
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import com.ichi2.anki.CollectionHelper
+import com.ichi2.anki.DeckMetaDataPreference
+import com.ichi2.libanki.sched.Counts
+import timber.log.Timber
+
+/**
+ * This Worker is responsible to Collect all the metadata and store it in share preference.
+ * Technically it refreshes the Deck Meta Data. Whenever this service is called
+ * then I will collect the new data of decks.
+ * */
+class DeckMetaDataWorker(val context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
+
+ private lateinit var colHelper: CollectionHelper
+
+ override fun doWork(): Result {
+
+ colHelper = CollectionHelper.getInstance()
+
+ Timber.tag("META").e("Deck Meta Data Worker started at: ${colHelper.getTimeSafe(context).currentDate}")
+
+ // Update the data of Deck Metadata from HERE
+ val col = colHelper.getCol(context)
+ val deckList = col.sched.deckDueList()
+
+ deckList.forEach {
+ val new = it?.newCount ?: -1
+ val lrn = it?.lrnCount ?: -1
+ val rev = it?.revCount ?: -1
+ val data = Meta(
+ it?.did ?: -1,
+ it?.fullDeckName ?: "Deck Name",
+ new,
+ lrn,
+ rev,
+ col.sched.eta(Counts(new, lrn, rev), false)
+ )
+ storeInPreference(data)
+ }
+
+ updateLastFetch(colHelper.getTimeSafe(context).toString())
+
+ return Result.success() // Done work successfully...
+ }
+
+ private fun updateLastFetch(time: String) {
+ val metaPreference = DeckMetaDataPreference(context)
+ metaPreference.putString(LAST_FETCH_TIME, time)
+ }
+
+ /**
+ * It is used to store the data in the DeckMetaData Shared Preference.
+ * */
+ private fun storeInPreference(list: Meta) {
+ val metaPreference = DeckMetaDataPreference(context)
+ metaPreference.setMetaData(list.did.toString(), list)
+ }
+
+ data class Meta(
+ val did: Long,
+ val deckName: String,
+ val new: Int,
+ val lrn: Int,
+ val rev: Int,
+ val eta: Int
+ )
+
+ companion object {
+ const val DECK_META_WORKER = "DeckMetaData"
+ const val LAST_FETCH_TIME = "LAST_FETCH"
+ }
+}