From 257bb949313aaca19c954100c90e185631996fe8 Mon Sep 17 00:00:00 2001 From: Prateek Singh <76490368+prateek-singh-3212@users.noreply.github.com> Date: Tue, 31 May 2022 23:46:17 +0530 Subject: [PATCH] Implemented Base for fetching Deck Meta Data --- AnkiDroid/build.gradle | 3 + AnkiDroid/src/main/AndroidManifest.xml | 5 + .../com/ichi2/anki/DeckMetaDataPreference.kt | 42 ++++++ .../main/java/com/ichi2/anki/IntentHandler.kt | 12 ++ .../anki/services/DeckMetaDataService.kt | 127 ++++++++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/DeckMetaDataPreference.kt create mode 100644 AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt diff --git a/AnkiDroid/build.gradle b/AnkiDroid/build.gradle index 8e81a4c290e1..0e670e535f44 100644 --- a/AnkiDroid/build.gradle +++ b/AnkiDroid/build.gradle @@ -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" diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml index b9a802893408..62377325650b 100644 --- a/AnkiDroid/src/main/AndroidManifest.xml +++ b/AnkiDroid/src/main/AndroidManifest.xml @@ -377,6 +377,11 @@ + + = 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 new file mode 100644 index 000000000000..fe8a67dc449d --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/services/DeckMetaDataService.kt @@ -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" + } +}