forked from recloudstream/cloudstream
Added delayed updating on A13 to make it less jarring
This commit is contained in:
parent
0afb6b62aa
commit
657971d008
7 changed files with 78 additions and 37 deletions
|
@ -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 ?: ""}")
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,7 +27,10 @@ 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.
|
||||||
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()
|
val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf()
|
||||||
|
@ -35,7 +39,7 @@ class CloudflareKiller : Interceptor {
|
||||||
* Gets the headers with cookies, webview user agent included!
|
* Gets the headers with cookies, webview user agent included!
|
||||||
* */
|
* */
|
||||||
fun getCookieHeaders(url: String): Headers {
|
fun getCookieHeaders(url: String): Headers {
|
||||||
val userAgentHeaders = WebViewResolver.webViewUserAgent?.let {
|
val userAgentHeaders = WebViewResolver.webViewUserAgent?.let {
|
||||||
mapOf("user-agent" to it)
|
mapOf("user-agent" to it)
|
||||||
} ?: emptyMap()
|
} ?: emptyMap()
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
|
||||||
return null
|
|
||||||
} finally {
|
|
||||||
if (input != null) {
|
|
||||||
try {
|
|
||||||
input.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} catch (ex: IOException) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
return line
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
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) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in a new issue