Split support for Android API 21 and 23
This commit is contained in:
41
app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/ApkInstaller.kt
vendored
Normal file
41
app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/ApkInstaller.kt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package io.nekohasekai.sfa.vendor
|
||||
|
||||
import android.content.Context
|
||||
import io.nekohasekai.sfa.database.Settings
|
||||
import java.io.File
|
||||
|
||||
enum class InstallMethod {
|
||||
PACKAGE_INSTALLER,
|
||||
ROOT,
|
||||
}
|
||||
|
||||
object ApkInstaller {
|
||||
|
||||
fun getConfiguredMethod(): InstallMethod {
|
||||
return if (Settings.silentInstallEnabled) {
|
||||
val method = Settings.silentInstallMethod
|
||||
if (method == "SHIZUKU") InstallMethod.ROOT else InstallMethod.valueOf(method)
|
||||
} else {
|
||||
InstallMethod.PACKAGE_INSTALLER
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun install(context: Context, apkFile: File, method: InstallMethod = getConfiguredMethod()): Result<Unit> {
|
||||
return when (method) {
|
||||
InstallMethod.ROOT -> RootInstaller.install(apkFile)
|
||||
InstallMethod.PACKAGE_INSTALLER -> SystemPackageInstaller.install(context, apkFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun canSystemSilentInstall(): Boolean {
|
||||
return SystemPackageInstaller.canSystemSilentInstall()
|
||||
}
|
||||
|
||||
suspend fun canSilentInstall(): Boolean {
|
||||
val method = getConfiguredMethod()
|
||||
return when (method) {
|
||||
InstallMethod.PACKAGE_INSTALLER -> canSystemSilentInstall()
|
||||
InstallMethod.ROOT -> RootInstaller.checkAccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
149
app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt
vendored
Normal file
149
app/src/otherLegacy/java/io/nekohasekai/sfa/vendor/Vendor.kt
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
package io.nekohasekai.sfa.vendor
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.nekohasekai.sfa.Application
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.database.Settings
|
||||
import io.nekohasekai.sfa.update.UpdateCheckException
|
||||
import io.nekohasekai.sfa.update.UpdateInfo
|
||||
import io.nekohasekai.sfa.update.UpdateState
|
||||
import io.nekohasekai.sfa.update.UpdateTrack
|
||||
|
||||
object Vendor : VendorInterface {
|
||||
private const val TAG = "Vendor"
|
||||
|
||||
override fun checkUpdate(
|
||||
activity: Activity,
|
||||
byUser: Boolean,
|
||||
) {
|
||||
try {
|
||||
val updateInfo = checkUpdateAsync()
|
||||
if (updateInfo != null) {
|
||||
activity.runOnUiThread {
|
||||
showUpdateDialog(activity, updateInfo)
|
||||
}
|
||||
} else if (byUser) {
|
||||
activity.runOnUiThread {
|
||||
showNoUpdatesDialog(activity)
|
||||
}
|
||||
}
|
||||
} catch (e: UpdateCheckException.TrackNotSupported) {
|
||||
Log.d(TAG, "checkUpdate: track not supported")
|
||||
if (byUser) {
|
||||
activity.runOnUiThread {
|
||||
showTrackNotSupportedDialog(activity)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "checkUpdate: ", e)
|
||||
if (byUser) {
|
||||
activity.runOnUiThread {
|
||||
showNoUpdatesDialog(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdateDialog(activity: Activity, updateInfo: UpdateInfo) {
|
||||
val message = buildString {
|
||||
append(activity.getString(R.string.new_version_available, updateInfo.versionName))
|
||||
if (!updateInfo.releaseNotes.isNullOrBlank()) {
|
||||
append("\n\n")
|
||||
append(updateInfo.releaseNotes.take(500))
|
||||
if (updateInfo.releaseNotes.length > 500) {
|
||||
append("...")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.check_update)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.update) { _, _ ->
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(updateInfo.releaseUrl))
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showNoUpdatesDialog(activity: Activity) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.check_update)
|
||||
.setMessage(R.string.no_updates_available)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showTrackNotSupportedDialog(activity: Activity) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.check_update)
|
||||
.setMessage(R.string.update_track_not_supported)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun createQRCodeAnalyzer(
|
||||
onSuccess: (String) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
): ImageAnalysis.Analyzer? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun isPerAppProxyAvailable(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun supportsTrackSelection(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun checkUpdateAsync(): UpdateInfo? {
|
||||
val track = UpdateTrack.fromString(Settings.updateTrack)
|
||||
return GitHubUpdateChecker().use { checker ->
|
||||
checker.checkUpdate(track)
|
||||
}
|
||||
}
|
||||
|
||||
override fun supportsSilentInstall(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun supportsAutoUpdate(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scheduleAutoUpdate() {
|
||||
UpdateWorker.schedule(io.nekohasekai.sfa.Application.application)
|
||||
}
|
||||
|
||||
override suspend fun verifySilentInstallMethod(method: String): Boolean {
|
||||
return when (method) {
|
||||
"PACKAGE_INSTALLER" -> {
|
||||
ApkInstaller.canSystemSilentInstall() &&
|
||||
Application.application.packageManager.canRequestPackageInstalls()
|
||||
}
|
||||
"ROOT" -> RootInstaller.checkAccess()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun downloadAndInstall(context: android.content.Context, downloadUrl: String): Result<Unit> {
|
||||
return try {
|
||||
val cachedApk = UpdateState.cachedApkFile.value
|
||||
val apkFile = if (cachedApk != null && cachedApk.exists() && cachedApk.length() > 0) {
|
||||
cachedApk
|
||||
} else {
|
||||
ApkDownloader().use { it.download(downloadUrl) }
|
||||
}
|
||||
ApkInstaller.install(context, apkFile)
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user