Updating Extension installer from upstream
Also adding an onerror handle
This commit is contained in:
parent
e0e072546f
commit
652e045acf
@ -6,7 +6,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Environment
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||||
@ -63,28 +63,28 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
// Register the receiver after removing (and unregistering) the previous download
|
// Register the receiver after removing (and unregistering) the previous download
|
||||||
downloadReceiver.register()
|
downloadReceiver.register()
|
||||||
|
|
||||||
val request = DownloadManager.Request(Uri.parse(url))
|
val downloadUri = Uri.parse(url)
|
||||||
.setTitle(extension.name)
|
val request = DownloadManager.Request(downloadUri)
|
||||||
.setMimeType(APK_MIME)
|
.setTitle(extension.name)
|
||||||
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
.setMimeType(APK_MIME)
|
||||||
|
.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment)
|
||||||
|
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||||
|
|
||||||
val id = downloadManager.enqueue(request)
|
val id = downloadManager.enqueue(request)
|
||||||
activeDownloads[pkgName] = id
|
activeDownloads[pkgName] = id
|
||||||
|
|
||||||
downloadsRelay.filter { it.first == id }
|
downloadsRelay.filter { it.first == id }
|
||||||
.map { it.second }
|
.map { it.second }
|
||||||
// Poll download status
|
// Poll download status
|
||||||
.mergeWith(pollStatus(id))
|
.mergeWith(pollStatus(id))
|
||||||
// Force an error if the download takes more than 3 minutes
|
// Force an error if the download takes more than 3 minutes
|
||||||
.mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
|
.mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
|
||||||
// Stop when the application is installed or errors
|
// Stop when the application is installed or errors
|
||||||
.takeUntil { it.isCompleted() }
|
.takeUntil { it.isCompleted() }
|
||||||
// Always notify on main thread
|
// Always notify on main thread
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
// Always remove the download when unsubscribed
|
// Always remove the download when unsubscribed
|
||||||
.doOnUnsubscribe {
|
.doOnUnsubscribe { deleteDownload(pkgName) }
|
||||||
deleteDownload(pkgName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,25 +97,28 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
val query = DownloadManager.Query().setFilterById(id)
|
val query = DownloadManager.Query().setFilterById(id)
|
||||||
|
|
||||||
return Observable.interval(0, 1, TimeUnit.SECONDS)
|
return Observable.interval(0, 1, TimeUnit.SECONDS)
|
||||||
// Get the current download status
|
// Get the current download status
|
||||||
.map {
|
.map {
|
||||||
downloadManager.query(query).use { cursor ->
|
downloadManager.query(query).use { cursor ->
|
||||||
cursor.moveToFirst()
|
cursor.moveToFirst()
|
||||||
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
|
cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Ignore duplicate results
|
}
|
||||||
.distinctUntilChanged()
|
// Ignore duplicate results
|
||||||
// Stop polling when the download fails or finishes
|
.distinctUntilChanged()
|
||||||
.takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED }
|
// Stop polling when the download fails or finishes
|
||||||
// Map to our model
|
.takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED }
|
||||||
.flatMap { status ->
|
// Map to our model
|
||||||
when (status) {
|
.flatMap { status ->
|
||||||
DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending)
|
when (status) {
|
||||||
DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading)
|
DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending)
|
||||||
else -> Observable.empty()
|
DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading)
|
||||||
}
|
else -> Observable.empty()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.doOnError {
|
||||||
|
Timber.e(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,9 +128,9 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
*/
|
*/
|
||||||
fun installApk(downloadId: Long, uri: Uri) {
|
fun installApk(downloadId: Long, uri: Uri) {
|
||||||
val intent = Intent(context, ExtensionInstallActivity::class.java)
|
val intent = Intent(context, ExtensionInstallActivity::class.java)
|
||||||
.setDataAndType(uri, APK_MIME)
|
.setDataAndType(uri, APK_MIME)
|
||||||
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
||||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
@ -161,7 +164,7 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
*
|
*
|
||||||
* @param pkgName The package name of the download to delete.
|
* @param pkgName The package name of the download to delete.
|
||||||
*/
|
*/
|
||||||
fun deleteDownload(pkgName: String) {
|
private fun deleteDownload(pkgName: String) {
|
||||||
val downloadId = activeDownloads.remove(pkgName)
|
val downloadId = activeDownloads.remove(pkgName)
|
||||||
if (downloadId != null) {
|
if (downloadId != null) {
|
||||||
downloadManager.remove(downloadId)
|
downloadManager.remove(downloadId)
|
||||||
@ -223,20 +226,15 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Due to a bug in Android versions prior to N, the installer can't open files that do
|
val query = DownloadManager.Query().setFilterById(id)
|
||||||
// not contain the extension in the path, even if you specify the correct MIME.
|
downloadManager.query(query).use { cursor ->
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
if (cursor.moveToFirst()) {
|
||||||
val query = DownloadManager.Query().setFilterById(id)
|
val localUri = cursor.getString(
|
||||||
downloadManager.query(query).use { cursor ->
|
cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
|
||||||
if (cursor.moveToFirst()) {
|
).removePrefix(FILE_SCHEME)
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
val uriCompat = File(cursor.getString(cursor.getColumnIndex(
|
installApk(id, File(localUri).getUriCompat(context))
|
||||||
DownloadManager.COLUMN_LOCAL_FILENAME))).getUriCompat(context)
|
|
||||||
installApk(id, uriCompat)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
installApk(id, uri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,5 +242,6 @@ internal class ExtensionInstaller(private val context: Context) {
|
|||||||
companion object {
|
companion object {
|
||||||
const val APK_MIME = "application/vnd.android.package-archive"
|
const val APK_MIME = "application/vnd.android.package-archive"
|
||||||
const val EXTRA_DOWNLOAD_ID = "ExtensionInstaller.extra.DOWNLOAD_ID"
|
const val EXTRA_DOWNLOAD_ID = "ExtensionInstaller.extra.DOWNLOAD_ID"
|
||||||
|
const val FILE_SCHEME = "file://"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user