Skip to content

Commit

Permalink
Implemented Base for fetching Deck Meta Data
Browse files Browse the repository at this point in the history
  • Loading branch information
prateek-singh-3212 committed May 31, 2022
1 parent 502ee7a commit 257bb94
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 0 deletions.
3 changes: 3 additions & 0 deletions AnkiDroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -328,5 +328,8 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test:rules:1.4.0'

// GSON
implementation 'com.google.code.gson:gson:2.9.0'
}
apply from: "./kotlinMigration.gradle"
5 changes: 5 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@

<!-- Service to perform web API queries -->
<service android:name="com.ichi2.widget.AnkiDroidWidgetSmall$UpdateService" />
<service
android:enabled="true"
android:name=".services.DeckMetaDataService"
android:exported="false"/>


<!-- small widget -->
<receiver
Expand Down
42 changes: 42 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/DeckMetaDataPreference.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.ichi2.anki

import android.content.Context
import android.content.SharedPreferences
import com.google.gson.Gson
import com.ichi2.anki.services.DeckMetaDataService
import timber.log.Timber

class DeckMetaDataPreference(context: Context) {

private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("DeckMetaData", Context.MODE_PRIVATE)

fun setString(key: String, value: String) {
sharedPreferences.edit()
.putString(key, value)
.apply()
}

fun getString(key: String, default: String): String {
return sharedPreferences.getString(key, default)!!
}

fun setMetaData(key: String, value: DeckMetaDataService.Meta) {
val json: String = Gson().toJson(value)
sharedPreferences.edit()
.putString(key, json)
.apply()
Timber.tag("META").e(json)
}

fun getMetaData(key: String): DeckMetaDataService.Meta? {
val jsonData = sharedPreferences
.getString(key, null)

return if (jsonData == null) {
null
} else {
Gson().fromJson(jsonData, DeckMetaDataService.Meta::class.java)
}
}
}
12 changes: 12 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/IntentHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ 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
Expand All @@ -48,6 +49,7 @@ class IntentHandler : Activity() {
Timber.d("onCreate()")
super.onCreate(savedInstanceState)
disableXiaomiForceDarkMode(this)
launchDeckMetaDataService()
setContentView(R.layout.progress_bar)
val intent = intent
Timber.v(intent.toString())
Expand Down Expand Up @@ -136,6 +138,16 @@ 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 {
Expand Down
127 changes: 127 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
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 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
import java.util.*

class DeckMetaDataService : Service() {

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

Timber.tag("META").e("On Service start command...")

/**
* 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(PRIORITY_LOW)
.setSilent(true)
.setCategory(Notification.CATEGORY_SERVICE)
.build()

startForeground(FOREGROUND_SERVICE_ID, notification)

// Update the data of Deck Metadata from HERE
val col = CollectionHelper.getInstance().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()

stopSelf() // Stops the current running service.
return START_NOT_STICKY
}

private fun updateLastFetch() {
val metaPreference = DeckMetaDataPreference(this)
metaPreference.setString(LAST_FETCH_TIME, System.currentTimeMillis().toString())
}

/**
* 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 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,
System.currentTimeMillis() + interval,
pendingIntent
)
Timber.tag("META").e("Service will start again at %s", (Time.calendar(System.currentTimeMillis() + interval).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"
}
}

0 comments on commit 257bb94

Please sign in to comment.