Added delayed updating on A13 to make it less jarring

This commit is contained in:
Blatzar 2023-01-03 20:56:03 +01:00
parent 0afb6b62aa
commit 657971d008
7 changed files with 78 additions and 37 deletions

View file

@ -48,7 +48,7 @@ android {
targetSdk = 33 targetSdk = 33
versionCode = 55 versionCode = 55
versionName = "3.3.0" versionName = "3.4.0"
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}") resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")

View file

@ -4,25 +4,20 @@ import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.WindowManager import android.view.WindowManager
import android.widget.FrameLayout import android.widget.Toast
import android.widget.LinearLayout
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginRight
import androidx.core.view.setMargins
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentContainerView
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavDestination.Companion.hierarchy
@ -77,6 +72,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateT
import com.lagradost.cloudstream3.ui.settings.SettingsGeneral import com.lagradost.cloudstream3.ui.settings.SettingsGeneral
import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY
import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.loadCache import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.loadRepository import com.lagradost.cloudstream3.utils.AppUtils.loadRepository
@ -87,8 +83,6 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
import com.lagradost.cloudstream3.utils.Event
import com.lagradost.cloudstream3.utils.IOnBackPressed
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
@ -97,9 +91,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
import com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API
import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.ResponseParser import com.lagradost.nicehttp.ResponseParser
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
@ -475,6 +466,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
// Start any delayed updates
if (ApkInstaller.delayedInstaller?.startInstallation() == true) {
Toast.makeText(this, R.string.update_started, Toast.LENGTH_LONG).show()
}
try { try {
if (isCastApiAvailable()) { if (isCastApiAvailable()) {
mSessionManager.removeSessionManagerListener(mSessionManagerListener) mSessionManager.removeSessionManagerListener(mSessionManagerListener)

View file

@ -5,6 +5,7 @@ import android.webkit.CookieManager
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.debugWarning import com.lagradost.cloudstream3.mvvm.debugWarning
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.nicehttp.Requests.Companion.await import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.cookies import com.lagradost.nicehttp.cookies
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -26,8 +27,11 @@ class CloudflareKiller : Interceptor {
init { init {
// Needs to clear cookies between sessions to generate new cookies. // Needs to clear cookies between sessions to generate new cookies.
normalSafeApiCall {
// This can throw an exception on unsupported devices :(
CookieManager.getInstance().removeAllCookies(null) CookieManager.getInstance().removeAllCookies(null)
} }
}
val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf() val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf()

View file

@ -296,12 +296,21 @@ class InAppUpdater {
val context = this val context = this
builder.apply { builder.apply {
setPositiveButton(R.string.update) { _, _ -> setPositiveButton(R.string.update) { _, _ ->
// Forcefully start any delayed installations
if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton
showToast(context, R.string.download_started, Toast.LENGTH_LONG) showToast(context, R.string.download_started, Toast.LENGTH_LONG)
// Check if the setting hasn't been changed // Check if the setting hasn't been changed
if (settingsManager.getInt(getString(R.string.apk_installer_key), -1) == -1) { if (settingsManager.getInt(
getString(R.string.apk_installer_key),
-1
) == -1
) {
if (isMiUi()) // Set to legacy if using miui if (isMiUi()) // Set to legacy if using miui
settingsManager.edit().putInt(getString(R.string.apk_installer_key), 1).apply() settingsManager.edit()
.putInt(getString(R.string.apk_installer_key), 1)
.apply()
} }
val currentInstaller = val currentInstaller =
@ -358,30 +367,19 @@ class InAppUpdater {
return false return false
} }
fun isMiUi(): Boolean { private fun isMiUi(): Boolean {
return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name")) return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name"))
} }
fun getSystemProperty(propName: String): String? { private fun getSystemProperty(propName: String): String? {
var line: String? = null return try {
var input: BufferedReader? = null
try {
val p = Runtime.getRuntime().exec("getprop $propName") val p = Runtime.getRuntime().exec("getprop $propName")
input = BufferedReader(InputStreamReader(p.inputStream), 1024) BufferedReader(InputStreamReader(p.inputStream), 1024).use {
line = input.readLine() it.readLine()
input.close() }
} catch (ex: IOException) { } catch (ex: IOException) {
return null null
} finally {
if (input != null) {
try {
input.close()
} catch (e: IOException) {
e.printStackTrace()
} }
} }
} }
return line
}
}
} }

View file

@ -5,15 +5,42 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.IntentSender
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.os.Build import android.os.Build
import android.widget.Toast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.utils.Coroutines.main
import java.io.InputStream import java.io.InputStream
const val INSTALL_ACTION = "ApkInstaller.INSTALL_ACTION" const val INSTALL_ACTION = "ApkInstaller.INSTALL_ACTION"
class ApkInstaller(private val service: PackageInstallerService) { class ApkInstaller(private val service: PackageInstallerService) {
companion object {
/**
* Used for postponed installations
**/
var delayedInstaller: DelayedInstaller? = null
}
inner class DelayedInstaller(
private val session: PackageInstaller.Session,
private val intent: IntentSender
) {
fun startInstallation(): Boolean {
return try {
session.commit(intent)
true
} catch (e: Exception) {
false
}.also { delayedInstaller = null }
}
}
private val packageInstaller = service.packageManager.packageInstaller private val packageInstaller = service.packageManager.packageInstaller
enum class InstallProgressStatus { enum class InstallProgressStatus {
@ -76,7 +103,6 @@ class ApkInstaller(private val service: PackageInstallerService) {
inputStream.close() inputStream.close()
} }
installProgressStatus.invoke(InstallProgressStatus.Installing)
val intentSender = PendingIntent.getBroadcast( val intentSender = PendingIntent.getBroadcast(
service, service,
@ -85,7 +111,22 @@ class ApkInstaller(private val service: PackageInstallerService) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0,
).intentSender ).intentSender
// Use delayed installations on android 13 and only if "allow from unknown sources" is enabled
// if the app lacks installation permission it cannot ask for the permission when it's closed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
context.packageManager.canRequestPackageInstalls()
) {
// Save for later installation since it's more jarring to have the app exit abruptly
delayedInstaller = DelayedInstaller(session, intentSender)
main {
// Use real toast since it should show even if app is exited
Toast.makeText(context, R.string.delayed_update_notice, Toast.LENGTH_LONG)
.show()
}
} else {
installProgressStatus.invoke(InstallProgressStatus.Installing)
session.commit(intentSender) session.commit(intentSender)
}
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)

View file

@ -187,7 +187,7 @@ class PackageInstallerService : Service() {
const val UPDATE_CHANNEL_ID = "cloudstream3.updates" const val UPDATE_CHANNEL_ID = "cloudstream3.updates"
const val UPDATE_CHANNEL_NAME = "App Updates" const val UPDATE_CHANNEL_NAME = "App Updates"
const val UPDATE_CHANNEL_DESCRIPTION = "App updates notification channel" const val UPDATE_CHANNEL_DESCRIPTION = "App updates notification channel"
const val UPDATE_NOTIFICATION_ID = -68454136 const val UPDATE_NOTIFICATION_ID = -68454136 // Random unique
fun getIntent( fun getIntent(
context: Context, context: Context,

View file

@ -137,6 +137,7 @@
<string name="download_canceled">Download Canceled</string> <string name="download_canceled">Download Canceled</string>
<string name="download_done">Download Done</string> <string name="download_done">Download Done</string>
<string name="download_format" translatable="false">%s - %s</string> <string name="download_format" translatable="false">%s - %s</string>
<string name="update_started">Update Started</string>
<string name="stream">Stream</string> <string name="stream">Stream</string>
<string name="error_loading_links_toast">Error Loading Links</string> <string name="error_loading_links_toast">Error Loading Links</string>
<string name="download_storage_text">Internal Storage</string> <string name="download_storage_text">Internal Storage</string>
@ -611,5 +612,6 @@
<string name="apk_installer_legacy">Legacy</string> <string name="apk_installer_legacy">Legacy</string>
<string name="apk_installer_package_installer">PackageInstaller</string> <string name="apk_installer_package_installer">PackageInstaller</string>
<string name="delayed_update_notice">App will be updated upon exit</string>
</resources> </resources>