-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
323 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
<uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" /> | ||
|
||
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
android/shared/src/androidMain/kotlin/io/rebble/cobble/shared/jobs/AndroidJobScheduler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package io.rebble.cobble.shared.jobs | ||
|
||
import android.app.job.JobInfo | ||
import android.app.job.JobScheduler | ||
import android.content.ComponentName | ||
import android.content.Context | ||
import android.os.Build | ||
import org.koin.core.component.KoinComponent | ||
import org.koin.core.component.inject | ||
import kotlin.time.Duration.Companion.hours | ||
|
||
class AndroidJobScheduler: KoinComponent { | ||
private val context: Context by inject() | ||
private val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler | ||
|
||
companion object { | ||
private const val LOCKER_SYNC_JOB_ID = 1 | ||
private val LOCKER_SYNC_JOB_PERIOD = 5.hours | ||
} | ||
fun scheduleStartupJobs() { | ||
scheduleLockerSyncPeriodic() | ||
} | ||
|
||
private fun buildLockerSyncJob() = JobInfo.Builder(LOCKER_SYNC_JOB_ID, ComponentName(context.applicationContext, AndroidLockerSyncJob::class.java)) | ||
|
||
fun scheduleLockerSyncPeriodic() { | ||
val jobInfo = buildLockerSyncJob() | ||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) | ||
.setPeriodic(LOCKER_SYNC_JOB_PERIOD.inWholeMilliseconds) | ||
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
jobInfo.setPriority(JobInfo.PRIORITY_LOW) | ||
} | ||
|
||
jobScheduler.schedule(jobInfo.build()) | ||
} | ||
|
||
fun scheduleLockerSync(userInitiated: Boolean) { | ||
val jobInfo = buildLockerSyncJob() | ||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) | ||
if (userInitiated) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { | ||
jobInfo.setUserInitiated(true) | ||
} | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
jobInfo.setPriority(JobInfo.PRIORITY_HIGH) | ||
} | ||
} | ||
jobScheduler.schedule(jobInfo.build()) | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
android/shared/src/androidMain/kotlin/io/rebble/cobble/shared/jobs/AndroidLockerSyncJob.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package io.rebble.cobble.shared.jobs | ||
|
||
import android.app.job.JobParameters | ||
import android.app.job.JobService | ||
import android.os.Build | ||
import io.rebble.cobble.shared.Logging | ||
import kotlinx.coroutines.* | ||
import org.koin.core.component.KoinComponent | ||
import kotlin.coroutines.CoroutineContext | ||
|
||
class AndroidLockerSyncJob( | ||
private val coroutineContext: CoroutineContext = Dispatchers.Default | ||
): JobService(), KoinComponent { | ||
private lateinit var scope: CoroutineScope | ||
private val lockerSyncJob = LockerSyncJob() | ||
|
||
override fun onStartJob(params: JobParameters?): Boolean { | ||
require(params != null) { "Job parameters must not be null" } | ||
scope = CoroutineScope(coroutineContext + makeAndroidJobExceptionHandler(params, this::jobFinished)) | ||
scope.launch { | ||
if (lockerSyncJob.beginSync()) { | ||
jobFinished(params, false) | ||
} else { | ||
Logging.i("Locker sync failed, rescheduling") | ||
jobFinished(params, true) | ||
} | ||
} | ||
return true | ||
} | ||
|
||
override fun onStopJob(params: JobParameters?): Boolean { | ||
require(params != null) { "Job parameters must not be null" } | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
scope.cancel("Job stopped: ${params.stopReason}") | ||
} else { | ||
scope.cancel() | ||
} | ||
return true | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
.../shared/src/androidMain/kotlin/io/rebble/cobble/shared/jobs/androidJobExceptionHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package io.rebble.cobble.shared.jobs | ||
|
||
import android.app.job.JobParameters | ||
import io.rebble.cobble.shared.Logging | ||
import kotlinx.coroutines.CoroutineExceptionHandler | ||
|
||
fun makeAndroidJobExceptionHandler(jobParams: JobParameters, jobFinished: (params: JobParameters, wantsReschedule: Boolean) -> Unit) = CoroutineExceptionHandler { _, throwable -> | ||
Logging.e("Job failed, will reschedule", throwable) | ||
jobFinished(jobParams, true) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
android/shared/src/commonMain/kotlin/io/rebble/cobble/shared/database/dao/LockerDao.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package io.rebble.cobble.shared.database.dao | ||
|
||
import androidx.room.Dao | ||
import androidx.room.Insert | ||
import androidx.room.OnConflictStrategy | ||
import androidx.room.Query | ||
import io.rebble.cobble.shared.database.NextSyncAction | ||
import io.rebble.cobble.shared.database.entity.SyncedLockerEntry | ||
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryWithPlatforms | ||
|
||
@Dao | ||
interface LockerDao { | ||
@Insert(onConflict = OnConflictStrategy.REPLACE) | ||
suspend fun insertOrReplace(entry: SyncedLockerEntryWithPlatforms) | ||
|
||
@Insert(onConflict = OnConflictStrategy.REPLACE) | ||
suspend fun insertOrReplaceAll(entries: List<SyncedLockerEntryWithPlatforms>) | ||
|
||
@Query("SELECT * FROM SyncedLockerEntry WHERE id = :id") | ||
suspend fun getEntry(id: String): SyncedLockerEntryWithPlatforms? | ||
|
||
@Query("SELECT * FROM SyncedLockerEntry") | ||
suspend fun getAllEntries(): List<SyncedLockerEntryWithPlatforms> | ||
|
||
@Query("DELETE FROM SyncedLockerEntryPlatform WHERE lockerEntryId = :entryId") | ||
suspend fun clearPlatformsFor(entryId: String) | ||
|
||
@Query("UPDATE SyncedLockerEntry SET nextSyncAction = :action WHERE id = :id") | ||
suspend fun setNextSyncAction(id: String, action: NextSyncAction) | ||
|
||
@Query("UPDATE SyncedLockerEntry SET nextSyncAction = :action WHERE id IN (:ids)") | ||
suspend fun setNextSyncAction(ids: Set<String>, action: NextSyncAction) | ||
} |
83 changes: 83 additions & 0 deletions
83
...shared/src/commonMain/kotlin/io/rebble/cobble/shared/database/entity/SyncedLockerEntry.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package io.rebble.cobble.shared.database.entity | ||
|
||
import androidx.room.* | ||
import io.rebble.cobble.shared.database.NextSyncAction | ||
|
||
@Entity( | ||
indices = [ | ||
Index(value = ["uuid"], unique = true), | ||
] | ||
) | ||
data class SyncedLockerEntry( | ||
@PrimaryKey | ||
val id: String, | ||
val uuid: String, | ||
val version: String, | ||
val title: String, | ||
val type: String, | ||
val hearts: Int, | ||
val developerName: String, | ||
val configurable: Boolean, | ||
val timelineEnabled: Boolean, | ||
val removeLink: String, | ||
val shareLink: String, | ||
val pbwLink: String, | ||
val pbwReleaseId: String, | ||
val nextSyncAction: NextSyncAction | ||
) | ||
|
||
data class SyncedLockerEntryWithPlatforms( | ||
@Embedded | ||
val entry: SyncedLockerEntry, | ||
@Relation( | ||
parentColumn = "id", | ||
entityColumn = "lockerEntryId" | ||
) | ||
val platforms: List<SyncedLockerEntryPlatform> | ||
) | ||
|
||
@Entity( | ||
foreignKeys = [ | ||
androidx.room.ForeignKey( | ||
entity = SyncedLockerEntry::class, | ||
parentColumns = ["id"], | ||
childColumns = ["lockerEntryId"], | ||
onDelete = androidx.room.ForeignKey.CASCADE | ||
) | ||
], | ||
indices = [ | ||
Index(value = ["lockerEntryId"]), | ||
] | ||
) | ||
data class SyncedLockerEntryPlatform( | ||
@PrimaryKey(autoGenerate = true) | ||
val platformEntryId: Int, | ||
val lockerEntryId: String, | ||
val sdkVersion: String, | ||
val processInfoFlags: Int, | ||
val name: String, | ||
val description: String, | ||
val icon: String, | ||
) | ||
|
||
/** | ||
* Compare the data of this [SyncedLockerEntry] with another [SyncedLockerEntry] ignoring auto-generated fields. | ||
*/ | ||
fun SyncedLockerEntryWithPlatforms.dataEqualTo(other: SyncedLockerEntryWithPlatforms): Boolean { | ||
return entry == other.entry && | ||
platforms.all { platform -> | ||
other.platforms.any { it.dataEqualTo(platform) } | ||
} | ||
} | ||
|
||
/** | ||
* Compare the data of this [SyncedLockerEntryPlatform] with another [SyncedLockerEntryPlatform] ignoring auto-generated fields. | ||
*/ | ||
fun SyncedLockerEntryPlatform.dataEqualTo(other: SyncedLockerEntryPlatform): Boolean { | ||
return lockerEntryId == other.lockerEntryId && | ||
sdkVersion == other.sdkVersion && | ||
processInfoFlags == other.processInfoFlags && | ||
name == other.name && | ||
description == other.description && | ||
icon == other.icon | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.