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
versionCode = 55
versionName = "3.3.0"
versionName = "3.4.0"
resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}")

View file

@ -4,25 +4,20 @@ import android.content.ComponentName
import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.core.view.marginRight
import androidx.core.view.setMargins
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentContainerView
import androidx.navigation.NavController
import androidx.navigation.NavDestination
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.setup.HAS_DONE_SETUP_KEY
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.loadCache
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.setKey
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.UIHelper.changeStatusBarState
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.navigate
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.ResponseParser
import kotlinx.android.synthetic.main.activity_main.*
@ -475,6 +466,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
override fun onPause() {
super.onPause()
// Start any delayed updates
if (ApkInstaller.delayedInstaller?.startInstallation() == true) {
Toast.makeText(this, R.string.update_started, Toast.LENGTH_LONG).show()
}
try {
if (isCastApiAvailable()) {
mSessionManager.removeSessionManagerListener(mSessionManagerListener)

View file

@ -5,6 +5,7 @@ import android.webkit.CookieManager
import androidx.annotation.AnyThread
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.debugWarning
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.cookies
import kotlinx.coroutines.runBlocking
@ -26,7 +27,10 @@ class CloudflareKiller : Interceptor {
init {
// Needs to clear cookies between sessions to generate new cookies.
CookieManager.getInstance().removeAllCookies(null)
normalSafeApiCall {
// This can throw an exception on unsupported devices :(
CookieManager.getInstance().removeAllCookies(null)
}
}
val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf()
@ -35,7 +39,7 @@ class CloudflareKiller : Interceptor {
* Gets the headers with cookies, webview user agent included!
* */
fun getCookieHeaders(url: String): Headers {
val userAgentHeaders = WebViewResolver.webViewUserAgent?.let {
val userAgentHeaders = WebViewResolver.webViewUserAgent?.let {
mapOf("user-agent" to it)
} ?: emptyMap()

View file

@ -296,12 +296,21 @@ class InAppUpdater {
val context = this
builder.apply {
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)
// 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
settingsManager.edit().putInt(getString(R.string.apk_installer_key), 1).apply()
settingsManager.edit()
.putInt(getString(R.string.apk_installer_key), 1)
.apply()
}
val currentInstaller =
@ -358,30 +367,19 @@ class InAppUpdater {
return false
}
fun isMiUi(): Boolean {
private fun isMiUi(): Boolean {
return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name"))
}
fun getSystemProperty(propName: String): String? {
var line: String? = null
var input: BufferedReader? = null
try {
private fun getSystemProperty(propName: String): String? {
return try {
val p = Runtime.getRuntime().exec("getprop $propName")
input = BufferedReader(InputStreamReader(p.inputStream), 1024)
line = input.readLine()
input.close()
} catch (ex: IOException) {
return null
} finally {
if (input != null) {
try {
input.close()
} catch (e: IOException) {
e.printStackTrace()
}
BufferedReader(InputStreamReader(p.inputStream), 1024).use {
it.readLine()
}
} catch (ex: IOException) {
null
}
return line
}
}
}

View file

@ -5,15 +5,42 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.IntentSender
import android.content.pm.PackageInstaller
import android.os.Build
import android.widget.Toast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.utils.Coroutines.main
import java.io.InputStream
const val INSTALL_ACTION = "ApkInstaller.INSTALL_ACTION"
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
enum class InstallProgressStatus {
@ -76,7 +103,6 @@ class ApkInstaller(private val service: PackageInstallerService) {
inputStream.close()
}
installProgressStatus.invoke(InstallProgressStatus.Installing)
val intentSender = PendingIntent.getBroadcast(
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,
).intentSender
session.commit(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)
}
} catch (e: Exception) {
logError(e)

View file

@ -187,7 +187,7 @@ class PackageInstallerService : Service() {
const val UPDATE_CHANNEL_ID = "cloudstream3.updates"
const val UPDATE_CHANNEL_NAME = "App Updates"
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(
context: Context,

View file

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