diff --git a/.idea/gradle.xml b/.idea/gradle.xml index e5d9e072..04d9a444 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -8,7 +8,6 @@ - diff --git a/app/build.gradle b/app/build.gradle index e1c4392b..63a15b98 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,8 +35,8 @@ android { minSdkVersion 21 targetSdkVersion 30 - versionCode 40 - versionName "2.4.8" + versionCode 41 + versionName "2.5.8" resValue "string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}" diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 62cd8756..134ff6cb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -39,7 +39,6 @@ object APIHolder { WcoProvider(), // MeloMovieProvider(), // Captcha for links DubbedAnimeProvider(), - HDMProvider(), IHaveNoTvProvider(), // Documentaries provider //LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...) VMoveeProvider(), @@ -58,8 +57,6 @@ object APIHolder { //TmdbProvider(), - - FilmanProvider(), ZoroProvider(), @@ -81,6 +78,7 @@ object APIHolder { private val backwardsCompatibleProviders = arrayListOf( KawaiifuProvider(), // removed due to cloudflare + HDMProvider(),// removed due to cloudflare ) fun getApiFromName(apiName: String?): MainAPI { @@ -179,7 +177,8 @@ object APIHolder { fun Context.filterProviderByPreferredMedia(): List { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - val currentPrefMedia = settingsManager.getInt(this.getString(R.string.prefer_media_type_key), 0) + val currentPrefMedia = + settingsManager.getInt(this.getString(R.string.prefer_media_type_key), 0) val langs = this.getApiProviderLangSettings() val allApis = apis.filter { langs.contains(it.lang) }.filter { api -> api.hasMainPage } return if (currentPrefMedia < 1) { @@ -275,7 +274,7 @@ fun parseRating(ratingString: String?): Int? { return (floatRating * 10).toInt() } -fun MainAPI.fixUrlNull(url : String?) : String? { +fun MainAPI.fixUrlNull(url: String?): String? { if (url.isNullOrEmpty()) { return null } @@ -305,7 +304,7 @@ fun sortUrls(urls: Set): List { return urls.sortedBy { t -> -t.quality } } -fun sortSubs(subs : Set) : List { +fun sortSubs(subs: Set): List { return subs.sortedBy { it.name } } @@ -473,7 +472,7 @@ fun LoadResponse?.isAnimeBased(): Boolean { return (this.type == TvType.Anime || this.type == TvType.ONA) // && (this is AnimeLoadResponse) } -fun TvType?.isEpisodeBased() : Boolean { +fun TvType?.isEpisodeBased(): Boolean { if (this == null) return false return (this == TvType.TvSeries || this == TvType.Anime) } @@ -573,7 +572,13 @@ fun MainAPI.newMovieLoadResponse( dataUrl: String, initializer: MovieLoadResponse.() -> Unit = { } ): MovieLoadResponse { - val builder = MovieLoadResponse(name = name, url = url, apiName = this.name, type = type, dataUrl = dataUrl) + val builder = MovieLoadResponse( + name = name, + url = url, + apiName = this.name, + type = type, + dataUrl = dataUrl + ) builder.initializer() return builder } @@ -634,7 +639,13 @@ fun MainAPI.newTvSeriesLoadResponse( episodes: List, initializer: TvSeriesLoadResponse.() -> Unit = { } ): TvSeriesLoadResponse { - val builder = TvSeriesLoadResponse(name = name, url = url, apiName = this.name, type = type, episodes = episodes) + val builder = TvSeriesLoadResponse( + name = name, + url = url, + apiName = this.name, + type = type, + episodes = episodes + ) builder.initializer() return builder } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index 6e592982..d8d808e4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -1,26 +1,27 @@ package com.lagradost.cloudstream3.ui.player import android.annotation.SuppressLint -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter +import android.content.* import android.graphics.drawable.AnimatedImageDrawable import android.graphics.drawable.AnimatedVectorDrawable import android.media.metrics.PlaybackErrorEvent import android.os.Build import android.os.Bundle +import android.support.v4.media.session.MediaSessionCompat import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowManager import android.widget.Toast import androidx.annotation.LayoutRes import androidx.annotation.StringRes import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.media.session.MediaButtonReceiver import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.PlaybackException +import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.SubtitleView import com.lagradost.cloudstream3.AcraApplication.Companion.getKey @@ -81,9 +82,20 @@ abstract class AbstractPlayerFragment( throw NotImplementedError() } + private fun keepScreenOn(on : Boolean) { + if(on) { + activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } else { + activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + } + private fun updateIsPlaying(playing: Pair) { val (wasPlaying, isPlaying) = playing val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying + val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying + + keepScreenOn(!isPausedRightNow) isBuffering = CSPlayerLoading.IsBuffering == isPlaying if (isBuffering) { @@ -241,11 +253,48 @@ abstract class AbstractPlayerFragment( private fun playerUpdated(player: Any?) { if (player is ExoPlayer) { + context?.let { ctx -> + val mediaButtonReceiver = ComponentName(ctx, MediaButtonReceiver::class.java) + MediaSessionCompat(ctx, "Player", mediaButtonReceiver, null).let { media -> + //media.setCallback(mMediaSessionCallback) + //media.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS) + val mediaSessionConnector = MediaSessionConnector(media) + mediaSessionConnector.setPlayer(player) + media.isActive = true + mMediaSessionCompat = media + } + } + player_view?.player = player player_view?.performClick() } } + private var mediaSessionConnector: MediaSessionConnector? = null + private var mMediaSessionCompat: MediaSessionCompat? = null + + // this can be used in the future for players other than exoplayer + //private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() { + // override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { + // val keyEvent = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as KeyEvent? + // if (keyEvent != null) { + // if (keyEvent.action == KeyEvent.ACTION_DOWN) { // NO DOUBLE SKIP + // val consumed = when (keyEvent.keyCode) { + // KeyEvent.KEYCODE_MEDIA_PAUSE -> callOnPause() + // KeyEvent.KEYCODE_MEDIA_PLAY -> callOnPlay() + // KeyEvent.KEYCODE_MEDIA_STOP -> callOnStop() + // KeyEvent.KEYCODE_MEDIA_NEXT -> callOnNext() + // else -> false + // } + // if (consumed) return true + // } + // } + // + // return super.onMediaButtonEvent(mediaButtonEvent) + // } + //} + + @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { resizeMode = getKey(RESIZE_MODE_KEY) ?: 0 @@ -295,6 +344,7 @@ abstract class AbstractPlayerFragment( keyEventListener = null SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged + keepScreenOn(false) super.onDestroy() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt index 7fb4086a..f5f2b5ed 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt @@ -130,7 +130,7 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) { if (isShowing) { updateUIVisibility() } else { - player_holder.postDelayed({ updateUIVisibility() }, 200) + player_holder?.postDelayed({ updateUIVisibility() }, 200) } val titleMove = if (isShowing) 0f else -50.toPx.toFloat() diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index ab1ed075..1e84ac31 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -17,6 +17,7 @@ import com.hippo.unifile.UniFile import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType @@ -171,111 +172,115 @@ class GeneratorPlayer : FullScreenPlayer() { var selectSourceDialog: AlertDialog? = null override fun showMirrorsDialogue() { - currentSelectedSubtitles = player.getCurrentPreferredSubtitle() - context?.let { ctx -> - val isPlaying = player.getIsPlaying() - player.handleEvent(CSPlayerEvent.Pause) - val currentSubtitles = sortSubs(currentSubs) + try { + currentSelectedSubtitles = player.getCurrentPreferredSubtitle() + context?.let { ctx -> + val isPlaying = player.getIsPlaying() + player.handleEvent(CSPlayerEvent.Pause) + val currentSubtitles = sortSubs(currentSubs) - val sourceBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack) - .setView(R.layout.player_select_source_and_subs) + val sourceBuilder = AlertDialog.Builder(ctx, R.style.AlertDialogCustomBlack) + .setView(R.layout.player_select_source_and_subs) - val sourceDialog = sourceBuilder.create() - selectSourceDialog = sourceDialog - sourceDialog.show() - val providerList = - sourceDialog.findViewById(R.id.sort_providers)!! - val subtitleList = - sourceDialog.findViewById(R.id.sort_subtitles)!! - val applyButton = - sourceDialog.findViewById(R.id.apply_btt)!! - val cancelButton = - sourceDialog.findViewById(R.id.cancel_btt)!! + val sourceDialog = sourceBuilder.create() + selectSourceDialog = sourceDialog + sourceDialog.show() + val providerList = + sourceDialog.findViewById(R.id.sort_providers)!! + val subtitleList = + sourceDialog.findViewById(R.id.sort_subtitles)!! + val applyButton = + sourceDialog.findViewById(R.id.apply_btt)!! + val cancelButton = + sourceDialog.findViewById(R.id.cancel_btt)!! - val footer: TextView = - layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView - footer.text = ctx.getString(R.string.player_load_subtitles) - footer.setOnClickListener { - openSubPicker() - } - subtitleList.addFooterView(footer) - - var sourceIndex = 0 - var startSource = 0 - - val sortedUrls = sortLinks(useQualitySettings = false) - if (sortedUrls.isNullOrEmpty()) { - sourceDialog.findViewById(R.id.sort_sources_holder)?.isGone = true - } else { - startSource = sortedUrls.indexOf(currentSelectedLink) - sourceIndex = startSource - - val sourcesArrayAdapter = - ArrayAdapter(ctx, R.layout.sort_bottom_single_choice) - - sourcesArrayAdapter.addAll(sortedUrls.map { - it.first?.name ?: it.second?.name ?: "NULL" - }) - - providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE - providerList.adapter = sourcesArrayAdapter - providerList.setSelection(sourceIndex) - providerList.setItemChecked(sourceIndex, true) - - providerList.setOnItemClickListener { _, _, which, _ -> - sourceIndex = which - providerList.setItemChecked(which, true) + val footer: TextView = + layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView + footer.text = ctx.getString(R.string.player_load_subtitles) + footer.setOnClickListener { + openSubPicker() } - } + subtitleList.addFooterView(footer) - sourceDialog.setOnDismissListener { - if (isPlaying) { - player.handleEvent(CSPlayerEvent.Play) - } - activity?.hideSystemUI() - selectSourceDialog = null - } + var sourceIndex = 0 + var startSource = 0 - val subtitleIndexStart = currentSubtitles.indexOf(currentSelectedSubtitles) + 1 - var subtitleIndex = subtitleIndexStart + val sortedUrls = sortLinks(useQualitySettings = false) + if (sortedUrls.isNullOrEmpty()) { + sourceDialog.findViewById(R.id.sort_sources_holder)?.isGone = true + } else { + startSource = sortedUrls.indexOf(currentSelectedLink) + sourceIndex = startSource - val subsArrayAdapter = - ArrayAdapter(ctx, R.layout.sort_bottom_single_choice) - subsArrayAdapter.add(getString(R.string.no_subtitles)) - subsArrayAdapter.addAll(currentSubtitles.map { it.name }) + val sourcesArrayAdapter = + ArrayAdapter(ctx, R.layout.sort_bottom_single_choice) - subtitleList.adapter = subsArrayAdapter - subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE + sourcesArrayAdapter.addAll(sortedUrls.map { + it.first?.name ?: it.second?.name ?: "NULL" + }) - subtitleList.setSelection(subtitleIndex) - subtitleList.setItemChecked(subtitleIndex, true) + providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE + providerList.adapter = sourcesArrayAdapter + providerList.setSelection(sourceIndex) + providerList.setItemChecked(sourceIndex, true) - subtitleList.setOnItemClickListener { _, _, which, _ -> - subtitleIndex = which - subtitleList.setItemChecked(which, true) - } - - cancelButton.setOnClickListener { - sourceDialog.dismissSafe(activity) - } - - applyButton.setOnClickListener { - var init = false - if (sourceIndex != startSource) { - init = true - } - if (subtitleIndex != subtitleIndexStart) { - init = init || if (subtitleIndex <= 0) { - noSubtitles() - } else { - setSubtitles(currentSubtitles[subtitleIndex - 1]) + providerList.setOnItemClickListener { _, _, which, _ -> + sourceIndex = which + providerList.setItemChecked(which, true) } } - if (init) { - loadLink(sortedUrls[sourceIndex], true) + + sourceDialog.setOnDismissListener { + if (isPlaying) { + player.handleEvent(CSPlayerEvent.Play) + } + activity?.hideSystemUI() + selectSourceDialog = null + } + + val subtitleIndexStart = currentSubtitles.indexOf(currentSelectedSubtitles) + 1 + var subtitleIndex = subtitleIndexStart + + val subsArrayAdapter = + ArrayAdapter(ctx, R.layout.sort_bottom_single_choice) + subsArrayAdapter.add(getString(R.string.no_subtitles)) + subsArrayAdapter.addAll(currentSubtitles.map { it.name }) + + subtitleList.adapter = subsArrayAdapter + subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE + + subtitleList.setSelection(subtitleIndex) + subtitleList.setItemChecked(subtitleIndex, true) + + subtitleList.setOnItemClickListener { _, _, which, _ -> + subtitleIndex = which + subtitleList.setItemChecked(which, true) + } + + cancelButton.setOnClickListener { + sourceDialog.dismissSafe(activity) + } + + applyButton.setOnClickListener { + var init = false + if (sourceIndex != startSource) { + init = true + } + if (subtitleIndex != subtitleIndexStart) { + init = init || if (subtitleIndex <= 0) { + noSubtitles() + } else { + setSubtitles(currentSubtitles[subtitleIndex - 1]) + } + } + if (init) { + loadLink(sortedUrls[sourceIndex], true) + } + sourceDialog.dismissSafe(activity) } - sourceDialog.dismissSafe(activity) } + } catch (e : Exception) { + logError(e) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index 78a25eed..42bd02cd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -755,9 +755,13 @@ class ResultFragment : Fragment() { ACTION_PLAY_EPISODE_IN_BROWSER -> { acquireSingeExtractorLink(getString(R.string.episode_action_play_in_browser)) { link -> - val i = Intent(ACTION_VIEW) - i.data = Uri.parse(link.url) - startActivity(i) + try { + val i = Intent(ACTION_VIEW) + i.data = Uri.parse(link.url) + startActivity(i) + } catch (e : Exception) { + logError(e) + } } } @@ -1125,11 +1129,15 @@ class ResultFragment : Fragment() { } result_share?.setOnClickListener { - val i = Intent(ACTION_SEND) - i.type = "text/plain" - i.putExtra(EXTRA_SUBJECT, d.name) - i.putExtra(EXTRA_TEXT, d.url) - startActivity(createChooser(i, d.name)) + try { + val i = Intent(ACTION_SEND) + i.type = "text/plain" + i.putExtra(EXTRA_SUBJECT, d.name) + i.putExtra(EXTRA_TEXT, d.url) + startActivity(createChooser(i, d.name)) + } catch (e: Exception) { + logError(e) + } } updateSync(d.getId()) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt index fc6f526d..56aa5a0b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt @@ -32,6 +32,7 @@ import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.OAuth2API import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi @@ -301,22 +302,24 @@ class SettingsFragment : PreferenceFragmentCompat() { } fun getDownloadDirs(): List { - val defaultDir = getDownloadDir()?.filePath + return normalSafeApiCall { + val defaultDir = getDownloadDir()?.filePath - // app_name_download_path = Cloudstream and does not change depending on release. - // DOES NOT WORK ON SCOPED STORAGE. - val secondaryDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath + - File.separator + resources.getString(R.string.app_name_download_path) - val first = listOf(defaultDir, secondaryDir) - return (try { - val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second } + // app_name_download_path = Cloudstream and does not change depending on release. + // DOES NOT WORK ON SCOPED STORAGE. + val secondaryDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath + + File.separator + resources.getString(R.string.app_name_download_path) + val first = listOf(defaultDir, secondaryDir) + (try { + val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second } - (first + - requireContext().getExternalFilesDirs("").mapNotNull { it.path } + - currentDir) - } catch (e: Exception) { - first - }).filterNotNull().distinct() + (first + + requireContext().getExternalFilesDirs("").mapNotNull { it.path } + + currentDir) + } catch (e: Exception) { + first + }).filterNotNull().distinct() + } ?: emptyList() } downloadPathPreference.setOnPreferenceClickListener { diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt index 137f3b31..4996c1bf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt @@ -126,7 +126,12 @@ class InAppUpdater { } )!! < 0 else false return if (foundVersion != null) { - Update(shouldUpdate, foundAsset.browser_download_url, foundVersion.groupValues[2], found.body) + Update( + shouldUpdate, + foundAsset.browser_download_url, + foundVersion.groupValues[2], + found.body + ) } else { Update(false, null, null, null) } @@ -135,7 +140,8 @@ class InAppUpdater { } private fun Activity.getPreReleaseUpdate(): Update { - val tagUrl = "https://api.github.com/repos/LagradOst/CloudStream-3/git/ref/tags/pre-release" + val tagUrl = + "https://api.github.com/repos/LagradOst/CloudStream-3/git/ref/tags/pre-release" val releaseUrl = "https://api.github.com/repos/LagradOst/CloudStream-3/releases" val headers = mapOf("Accept" to "application/vnd.github.v3+json") val response = @@ -150,10 +156,16 @@ class InAppUpdater { val tagResponse = mapper.readValue(app.get(tagUrl, headers = headers).text) - val shouldUpdate = (getString(R.string.prerelease_commit_hash) != tagResponse.github_object.sha) + val shouldUpdate = + (getString(R.string.prerelease_commit_hash) != tagResponse.github_object.sha) return if (foundAsset != null) { - Update(shouldUpdate, foundAsset.browser_download_url, tagResponse.github_object.sha, found.body) + Update( + shouldUpdate, + foundAsset.browser_download_url, + tagResponse.github_object.sha, + found.body + ) } else { Update(false, null, null, null) } @@ -217,26 +229,33 @@ class InAppUpdater { } fun openApk(context: Context, uri: Uri) { - uri.path?.let { - val contentUri = FileProvider.getUriForFile( - context, - BuildConfig.APPLICATION_ID + ".provider", - File(it) - ) - val installIntent = Intent(Intent.ACTION_VIEW).apply { - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) - data = contentUri + try { + uri.path?.let { + val contentUri = FileProvider.getUriForFile( + context, + BuildConfig.APPLICATION_ID + ".provider", + File(it) + ) + val installIntent = Intent(Intent.ACTION_VIEW).apply { + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) + data = contentUri + } + context.startActivity(installIntent) } - context.startActivity(installIntent) + } catch (e: Exception) { + logError(e) } } fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if (!checkAutoUpdate || settingsManager.getBoolean(getString(R.string.auto_update_key), true) + if (!checkAutoUpdate || settingsManager.getBoolean( + getString(R.string.auto_update_key), + true + ) ) { val update = getAppUpdate() if (update.shouldUpdate && update.updateURL != null) { @@ -264,7 +283,8 @@ class InAppUpdater { showToast(context, R.string.download_started, Toast.LENGTH_LONG) thread { val downloadStatus = - normalSafeApiCall { context.downloadUpdate(update.updateURL) } ?: false + normalSafeApiCall { context.downloadUpdate(update.updateURL) } + ?: false if (!downloadStatus) { runOnUiThread { showToast( @@ -281,7 +301,8 @@ class InAppUpdater { if (checkAutoUpdate) { setNeutralButton(R.string.dont_show_again) { _, _ -> - settingsManager.edit().putBoolean("auto_update", false).apply() + settingsManager.edit().putBoolean("auto_update", false) + .apply() } } }