-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Using the system DownloadManager on some emulators causes a very odd SSL bug linked to compression, which is impossible to disable on Android's DownloadManager requests due to the Accept-Encoding header always being overwritten. This commit creates a generic download manager interface for which there is an Android DownloadManager wrapper (like before) in addition to a Ktor wrapper (which disables compression)
- Loading branch information
1 parent
f736062
commit 98c0a2e
Showing
11 changed files
with
310 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
app/src/main/kotlin/com/aliucord/manager/di/DownloadManagerProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.aliucord.manager.di | ||
|
||
import com.aliucord.manager.manager.PreferencesManager | ||
import com.aliucord.manager.manager.download.* | ||
import com.aliucord.manager.patcher.util.Signer.getKoin | ||
import com.aliucord.manager.util.IS_PROBABLY_EMULATOR | ||
import org.koin.core.annotation.KoinInternalApi | ||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* Handle providing the correct install manager based on preferences and device type. | ||
*/ | ||
class DownloadManagerProvider(private val prefs: PreferencesManager) { | ||
fun getActiveDownloader(): IDownloadManager = | ||
getDownloader(prefs.downloader) | ||
|
||
@OptIn(KoinInternalApi::class) | ||
fun getDownloader(type: DownloaderSetting): IDownloadManager = | ||
getKoin().scopeRegistry.rootScope.get(clazz = type.downloaderClass) | ||
|
||
companion object { | ||
fun getDefaultDownloader(): DownloaderSetting { | ||
// Ktor downloader has specific fix for emulator | ||
return if (IS_PROBABLY_EMULATOR) { | ||
DownloaderSetting.Ktor | ||
} else { | ||
DownloaderSetting.Android | ||
} | ||
} | ||
} | ||
} | ||
|
||
enum class DownloaderSetting( | ||
// @StringRes | ||
// private val localizedName: Int, | ||
val downloaderClass: KClass<out IDownloadManager>, | ||
) { | ||
Android(AndroidDownloadManager::class), | ||
Ktor(KtorDownloadManager::class), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,10 @@ | ||
package com.aliucord.manager.di | ||
|
||
import android.app.Application | ||
import android.content.Context | ||
import com.aliucord.manager.manager.* | ||
import com.aliucord.manager.manager.PreferencesManager | ||
import org.koin.core.scope.Scope | ||
|
||
fun Scope.providePreferences(): PreferencesManager { | ||
val ctx: Context = get() | ||
return PreferencesManager(ctx.getSharedPreferences("preferences", Context.MODE_PRIVATE)) | ||
} | ||
|
||
fun Scope.provideDownloadManager(): DownloadManager { | ||
val application: Application = get() | ||
return DownloadManager(application) | ||
} | ||
|
||
fun Scope.providePathManager(): PathManager { | ||
val ctx: Context = get() | ||
return PathManager(ctx) | ||
} |
5 changes: 4 additions & 1 deletion
5
app/src/main/kotlin/com/aliucord/manager/manager/PreferencesManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,16 @@ | ||
package com.aliucord.manager.manager | ||
|
||
import android.content.SharedPreferences | ||
import com.aliucord.manager.di.DownloadManagerProvider | ||
import com.aliucord.manager.di.DownloaderSetting | ||
import com.aliucord.manager.manager.base.BasePreferenceManager | ||
import com.aliucord.manager.ui.components.Theme | ||
|
||
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) { | ||
var theme by enumPreference("theme", Theme.DARK) | ||
var dynamicColor by booleanPreference("dynamic_color", true) | ||
var devMode by booleanPreference("dev_mode", false) | ||
var installer by enumPreference("installer", InstallerSetting.PM) | ||
var downloader by enumPreference<DownloaderSetting>("downloader", DownloadManagerProvider.getDefaultDownloader()) | ||
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM) | ||
var keepPatchedApks by booleanPreference("keep_patched_apks", false) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
app/src/main/kotlin/com/aliucord/manager/manager/download/IDownloadManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.aliucord.manager.manager.download | ||
|
||
import android.app.DownloadManager | ||
import android.content.Context | ||
import java.io.File | ||
|
||
/** | ||
* Common interface for different implementations of starting and managing the lifetime of downloads. | ||
*/ | ||
interface IDownloadManager { | ||
/** | ||
* Start a cancellable download. | ||
* @param url Remote src url | ||
* @param out Target path to download to. It is assumed that the application has write permissions to this path. | ||
* @param onProgressUpdate An optional [ProgressListener] callback. | ||
*/ | ||
suspend fun download(url: String, out: File, onProgressUpdate: ProgressListener? = null): Result | ||
|
||
/** | ||
* A callback executed from a coroutine called every 100ms in order to provide | ||
* info about the current download. This should not perform long-running tasks as the delay will be offset. | ||
*/ | ||
fun interface ProgressListener { | ||
/** | ||
* @param progress The current download progress in a `[0,1]` range. If null, then the download is either | ||
* paused, pending, or waiting to retry. | ||
*/ | ||
fun onUpdate(progress: Float?) | ||
} | ||
|
||
/** | ||
* The state of a download after execution has been completed and the system-level [DownloadManager] has been cleaned up. | ||
*/ | ||
sealed interface Result { | ||
/** | ||
* The download succeeded successfully. | ||
* @param file The path that the download was downloaded to. | ||
*/ | ||
data class Success(val file: File) : Result | ||
|
||
/** | ||
* This download was interrupted and the in-progress file has been deleted. | ||
* @param systemTriggered Whether the cancellation happened from the system (ie. clicked cancel on the download notification) | ||
* Otherwise, this was caused by a coroutine cancellation. | ||
*/ | ||
data class Cancelled(val systemTriggered: Boolean) : Result | ||
|
||
/** | ||
* This download failed to complete due to an error. | ||
*/ | ||
abstract class Error : Result { | ||
/** | ||
* The full internal error representation. | ||
*/ | ||
abstract fun getDebugReason(): String | ||
|
||
/** | ||
* Simplified + translatable user facing reason for the failure. | ||
* If null is returned, then the [getDebugReason] will be used instead. | ||
*/ | ||
open fun getLocalizedReason(context: Context): String? = null | ||
} | ||
} | ||
} |
Oops, something went wrong.