129 lines
4.8 KiB
Kotlin
129 lines
4.8 KiB
Kotlin
|
package co.electriccoin.zcash.ui.screen.update
|
||
|
|
||
|
import android.content.Context
|
||
|
import androidx.activity.ComponentActivity
|
||
|
import co.electriccoin.zcash.ui.screen.update.model.UpdateInfo
|
||
|
import co.electriccoin.zcash.ui.screen.update.model.UpdateState
|
||
|
import com.google.android.play.core.appupdate.AppUpdateInfo
|
||
|
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
|
||
|
import com.google.android.play.core.appupdate.AppUpdateOptions
|
||
|
import com.google.android.play.core.install.model.ActivityResult
|
||
|
import com.google.android.play.core.install.model.AppUpdateType
|
||
|
import com.google.android.play.core.install.model.UpdateAvailability
|
||
|
import kotlinx.coroutines.channels.ProducerScope
|
||
|
import kotlinx.coroutines.channels.awaitClose
|
||
|
import kotlinx.coroutines.flow.Flow
|
||
|
import kotlinx.coroutines.flow.callbackFlow
|
||
|
|
||
|
class AppUpdateCheckerImp private constructor() : AppUpdateChecker {
|
||
|
|
||
|
companion object {
|
||
|
private const val DEFAULT_STALENESS_DAYS = 3
|
||
|
|
||
|
fun new() = AppUpdateCheckerImp()
|
||
|
}
|
||
|
|
||
|
override val stalenessDays = DEFAULT_STALENESS_DAYS
|
||
|
|
||
|
/**
|
||
|
* This function checks available app update released on Google Play. It returns UpdateInfo object
|
||
|
* encapsulated in Flow in case of high priority update or in case of staleness days passed.
|
||
|
*
|
||
|
* For setting up the PRIORITY of an update in Google Play
|
||
|
* https://developer.android.com/guide/playcore/in-app-updates/kotlin-java#update-priority.
|
||
|
*
|
||
|
* @param context
|
||
|
*
|
||
|
* @return UpdateInfo object encapsulated in Flow in case of conditions succeeded
|
||
|
*/
|
||
|
override fun newCheckForUpdateAvailabilityFlow(
|
||
|
context: Context
|
||
|
): Flow<UpdateInfo> = callbackFlow {
|
||
|
val appUpdateInfoTask = AppUpdateManagerFactory.create(context.applicationContext).appUpdateInfo
|
||
|
|
||
|
appUpdateInfoTask.addOnCompleteListener { infoTask ->
|
||
|
if (!infoTask.isSuccessful) {
|
||
|
emitFailure(this)
|
||
|
return@addOnCompleteListener
|
||
|
}
|
||
|
|
||
|
val appUpdateInfo = infoTask.result
|
||
|
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
|
||
|
appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
|
||
|
) {
|
||
|
// we force user to update immediately in case of high priority
|
||
|
// or in case of staleness days passed
|
||
|
if (isHighPriority(appUpdateInfo.updatePriority()) ||
|
||
|
(appUpdateInfo.clientVersionStalenessDays() ?: -1) >= stalenessDays
|
||
|
) {
|
||
|
emitSuccess(this, infoTask.result, UpdateState.Prepared)
|
||
|
} else {
|
||
|
emitSuccess(this, infoTask.result, UpdateState.Done)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
awaitClose {
|
||
|
// No resources to release
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private fun emitSuccess(producerScope: ProducerScope<UpdateInfo>, info: AppUpdateInfo, state: UpdateState) {
|
||
|
producerScope.trySend(
|
||
|
UpdateInfo(
|
||
|
getPriority(info.updatePriority()),
|
||
|
isHighPriority(info.updatePriority()),
|
||
|
info,
|
||
|
state
|
||
|
)
|
||
|
)
|
||
|
}
|
||
|
|
||
|
private fun emitFailure(producerScope: ProducerScope<UpdateInfo>) {
|
||
|
producerScope.trySend(
|
||
|
UpdateInfo(
|
||
|
AppUpdateChecker.Priority.LOW,
|
||
|
false,
|
||
|
null,
|
||
|
UpdateState.Failed
|
||
|
)
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function is used for triggering in-app update with IMMEDIATE app update type.
|
||
|
*
|
||
|
* The immediate update can result with these values:
|
||
|
* Activity.RESULT_OK: The user accepted and the update succeeded (which, in practice, your app
|
||
|
* never should never receive because it already updated).
|
||
|
* Activity.RESULT_CANCELED: The user denied or canceled the update.
|
||
|
* ActivityResult.RESULT_IN_APP_UPDATE_FAILED: The flow failed either during the user confirmation,
|
||
|
* the download, or the installation.
|
||
|
*
|
||
|
* @param activity
|
||
|
* @param appUpdateInfo object is necessary for starting the update process,
|
||
|
* for getting it see {@link #checkForUpdateAvailability()}
|
||
|
*/
|
||
|
override fun newStartUpdateFlow(
|
||
|
activity: ComponentActivity,
|
||
|
appUpdateInfo: AppUpdateInfo
|
||
|
): Flow<Int> = callbackFlow {
|
||
|
val appUpdateResultTask = AppUpdateManagerFactory.create(activity).startUpdateFlow(
|
||
|
appUpdateInfo,
|
||
|
activity,
|
||
|
AppUpdateOptions.defaultOptions(AppUpdateType.IMMEDIATE)
|
||
|
)
|
||
|
|
||
|
appUpdateResultTask.addOnCompleteListener { resultTask ->
|
||
|
if (resultTask.isSuccessful) {
|
||
|
trySend(resultTask.result)
|
||
|
} else {
|
||
|
trySend(ActivityResult.RESULT_IN_APP_UPDATE_FAILED)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
awaitClose {
|
||
|
// No resources to release
|
||
|
}
|
||
|
}
|
||
|
}
|