IdGenerator.kt
/*
* Copyright 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.work.impl.utils
import android.content.Context
import android.content.SharedPreferences
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.work.impl.WorkDatabase
import androidx.work.impl.model.Preference
import androidx.work.impl.utils.PreferenceUtils.INSERT_PREFERENCE
import java.util.concurrent.Callable
/**
* Generates unique IDs that are persisted in [SharedPreferences].
* @param workDatabase The [WorkDatabase] where metadata is persisted.
*/
class IdGenerator(private val workDatabase: WorkDatabase) {
/**
* Generates IDs for [android.app.job.JobInfo] jobs given a reserved range.
*/
fun nextJobSchedulerIdWithRange(minInclusive: Int, maxInclusive: Int): Int {
return workDatabase.runInTransaction(Callable {
var id = workDatabase.nextId(NEXT_JOB_SCHEDULER_ID_KEY)
if (id !in minInclusive..maxInclusive) {
// outside the range, re-start at minInclusive.
id = minInclusive
workDatabase.updatePreference(NEXT_JOB_SCHEDULER_ID_KEY, id + 1)
}
id
})
}
/**
* Generates IDs for [android.app.AlarmManager] work.
*/
fun nextAlarmManagerId(): Int {
return workDatabase.runInTransaction(Callable {
workDatabase.nextId(NEXT_ALARM_MANAGER_ID_KEY)
})
}
}
private fun WorkDatabase.nextId(key: String): Int {
val value = preferenceDao().getLongValue(key)
val id = value?.toInt() ?: INITIAL_ID
val nextId = if (id == Int.MAX_VALUE) INITIAL_ID else id + 1
updatePreference(key, nextId)
return id
}
private fun WorkDatabase.updatePreference(key: String, value: Int) =
this.preferenceDao().insertPreference(Preference(key, value.toLong()))
/** The initial id used for JobInfos and Alarms. */
const val INITIAL_ID = 0
const val NEXT_JOB_SCHEDULER_ID_KEY = "next_job_scheduler_id"
const val NEXT_ALARM_MANAGER_ID_KEY = "next_alarm_manager_id"
const val PREFERENCE_FILE_KEY = "androidx.work.util.id"
/**
* Migrates [IdGenerator] from [android.content.SharedPreferences] to the
* [WorkDatabase].
*
* @param context The application [Context]
*/
internal fun migrateLegacyIdGenerator(
context: Context,
sqLiteDatabase: SupportSQLiteDatabase
) {
val sharedPreferences = context.getSharedPreferences(PREFERENCE_FILE_KEY, Context.MODE_PRIVATE)
// Check to see if we have not migrated already.
if (sharedPreferences.contains(NEXT_JOB_SCHEDULER_ID_KEY) ||
sharedPreferences.contains(NEXT_JOB_SCHEDULER_ID_KEY)
) {
val nextJobId = sharedPreferences.getInt(NEXT_JOB_SCHEDULER_ID_KEY, INITIAL_ID)
val nextAlarmId = sharedPreferences.getInt(NEXT_ALARM_MANAGER_ID_KEY, INITIAL_ID)
sqLiteDatabase.beginTransaction()
try {
sqLiteDatabase.execSQL(INSERT_PREFERENCE, arrayOf(NEXT_JOB_SCHEDULER_ID_KEY, nextJobId))
sqLiteDatabase.execSQL(
INSERT_PREFERENCE, arrayOf(NEXT_ALARM_MANAGER_ID_KEY, nextAlarmId)
)
// Cleanup
sharedPreferences.edit().clear().apply()
sqLiteDatabase.setTransactionSuccessful()
} finally {
sqLiteDatabase.endTransaction()
}
}
}