├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── themes.xml │ │ │ │ └── strings.xml │ │ │ ├── values-land │ │ │ │ └── dimens.xml │ │ │ ├── values-w1240dp │ │ │ │ └── dimens.xml │ │ │ ├── values-w600dp │ │ │ │ └── dimens.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ ├── xml │ │ │ │ ├── network_security_config.xml │ │ │ │ ├── backup_rules.xml │ │ │ │ └── data_extraction_rules.xml │ │ │ ├── values-v23 │ │ │ │ └── themes.xml │ │ │ ├── layout │ │ │ │ ├── activity_main.xml │ │ │ │ ├── item_upload.xml │ │ │ │ ├── multiple_single_files_layout.xml │ │ │ │ ├── single_file_upload_layout.xml │ │ │ │ └── upload_multiple_files_simultaneously_layout.xml │ │ │ ├── values-night │ │ │ │ └── themes.xml │ │ │ └── drawable │ │ │ │ ├── ic_launcher_foreground.xml │ │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── dh │ │ │ │ └── updemo │ │ │ │ ├── FileItem.kt │ │ │ │ ├── FilesItem.kt │ │ │ │ ├── App.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── UploadAdapter.kt │ │ │ │ ├── SingleFileUploadActivity.kt │ │ │ │ ├── UploadMultipleFilesSimultaneouslyActivity.kt │ │ │ │ └── MultipleSingleFileUploadsActivity.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── dh │ │ │ └── updemo │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── dh │ │ └── updemo │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── quickupload ├── .gitignore ├── consumer-rules.pro ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── dh │ │ │ │ └── quickupload │ │ │ │ ├── data │ │ │ │ ├── UploadStatus.kt │ │ │ │ ├── UploadElapsedTime.kt │ │ │ │ ├── UploadRate.kt │ │ │ │ ├── RetryPolicyConfig.kt │ │ │ │ ├── NameValue.kt │ │ │ │ ├── UploadFile.kt │ │ │ │ ├── HttpUploadTaskParameters.kt │ │ │ │ ├── UploadTaskParameters.kt │ │ │ │ └── UploadInfo.kt │ │ │ │ ├── tools │ │ │ │ ├── datapreservation │ │ │ │ │ ├── Persistable.kt │ │ │ │ │ └── PersistableData.kt │ │ │ │ ├── translationfile │ │ │ │ │ ├── SchemeHandler.kt │ │ │ │ │ ├── FileSchemeHandler.kt │ │ │ │ │ └── ContentResolverSchemeHandler.kt │ │ │ │ └── logger │ │ │ │ │ ├── DefaultExt.kt │ │ │ │ │ └── Logger.kt │ │ │ │ ├── exceptions │ │ │ │ └── Exceptions.kt │ │ │ │ ├── network │ │ │ │ ├── BaseNetwork.kt │ │ │ │ ├── okhttp │ │ │ │ │ ├── OkHttpExtensions.kt │ │ │ │ │ ├── OkHttpBodyWriter.kt │ │ │ │ │ ├── OkHttpNetwork.kt │ │ │ │ │ └── OkHttpNetworkRequest.kt │ │ │ │ ├── ServerResponse.kt │ │ │ │ ├── NetworkRequest.kt │ │ │ │ └── BodyWriter.kt │ │ │ │ ├── observer │ │ │ │ ├── task │ │ │ │ │ ├── UploadTaskObserver.kt │ │ │ │ │ ├── TaskCompletionNotifier.kt │ │ │ │ │ └── UploadObserverBase.kt │ │ │ │ └── network │ │ │ │ │ └── NetworkMonitor.kt │ │ │ │ ├── quick │ │ │ │ ├── UploadFileExtensions.kt │ │ │ │ ├── QuickUploadRequest.kt │ │ │ │ └── QuickUploadTask.kt │ │ │ │ ├── GeneralUploadTask.kt │ │ │ │ ├── GeneralUploadRequest.kt │ │ │ │ ├── UploadRequest.kt │ │ │ │ ├── UploadConfiguration.kt │ │ │ │ ├── extensions │ │ │ │ └── Extensions.kt │ │ │ │ ├── UploadService.kt │ │ │ │ └── UploadTask.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── dh │ │ │ └── quickupload │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── dh │ │ └── quickupload │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── jitpack.yml ├── pictureresources ├── one.gif ├── two.gif └── three.gif ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── config.gradle ├── settings.gradle ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat ├── gradlew └── LICENSE /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /quickupload/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 -------------------------------------------------------------------------------- /quickupload/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pictureresources/one.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/pictureresources/one.gif -------------------------------------------------------------------------------- /pictureresources/two.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/pictureresources/two.gif -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | -------------------------------------------------------------------------------- /pictureresources/three.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/pictureresources/three.gif -------------------------------------------------------------------------------- /app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-w1240dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 200dp 3 | -------------------------------------------------------------------------------- /app/src/main/res/values-w600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | kotlin_version = "1.6.20" 3 | minsdk_version = 21 4 | targetsdk_version = 34 5 | compilesdk_version = 34 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XJ-Up/quickupload/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/data/UploadStatus.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.data 2 | 3 | enum class UploadStatus { 4 | DEFAULT, 5 | Wait, 6 | InProgress, 7 | Success, 8 | Error, 9 | Completed 10 | } 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri May 10 15:10:46 CST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/data/UploadElapsedTime.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.data 2 | 3 | /** 4 | * 上传时间 5 | */ 6 | data class UploadElapsedTime(val minutes: Int, val seconds: Int) { 7 | val totalSeconds: Int 8 | get() = minutes * 60 + seconds 9 | } 10 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/tools/datapreservation/Persistable.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.tools.datapreservation 2 | 3 | interface Persistable { 4 | fun toPersistableData(): PersistableData 5 | 6 | interface Creator { 7 | fun createFromPersistableData(data: PersistableData): T 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/data/UploadRate.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.data 2 | 3 | data class UploadRate(val value: Int = 0, val unit: UploadRateUnit = UploadRateUnit.BitPerSecond) { 4 | enum class UploadRateUnit { 5 | BitPerSecond, 6 | KilobitPerSecond, 7 | MegabitPerSecond 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/exceptions/Exceptions.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.exceptions 2 | 3 | import com.dh.quickupload.network.ServerResponse 4 | 5 | class UserCancelledUploadException : Throwable("用户已取消上传") 6 | class UploadError(val serverResponse: ServerResponse) : Throwable("上传错误") 7 | class NoNetworkException: Throwable("网络连接断开") 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/dh/updemo/FileItem.kt: -------------------------------------------------------------------------------- 1 | package com.dh.updemo 2 | 3 | import com.dh.quickupload.observer.task.UploadObserverBase 4 | 5 | /** 6 | * 单个地址文件上传示例 7 | * 使用: 8 | * 继承 UploadObserverBase() 9 | * 10 | */ 11 | data class FileItem( 12 | val fileName: String, 13 | val filePath: String, 14 | override val uploadId: String, 15 | ) : UploadObserverBase(uploadId) -------------------------------------------------------------------------------- /app/src/main/java/com/dh/updemo/FilesItem.kt: -------------------------------------------------------------------------------- 1 | package com.dh.updemo 2 | 3 | import com.dh.quickupload.observer.task.UploadObserverBase 4 | 5 | /** 6 | * 多个地址文件上传示例 7 | * 使用: 8 | * 继承 UploadObserverBase() 9 | * 10 | */ 11 | data class FilesItem( 12 | val fileName: String, 13 | val filePath: MutableList, 14 | override val uploadId: String, 15 | ) : UploadObserverBase(uploadId) 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/test/java/com/dh/updemo/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.dh.updemo 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /quickupload/src/test/java/com/dh/quickupload/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | 7 | } 8 | } 9 | dependencyResolutionManagement { 10 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 11 | repositories { 12 | google() 13 | mavenCentral() 14 | maven { url 'https://jitpack.io' } 15 | } 16 | } 17 | 18 | rootProject.name = "UpDemo" 19 | include ':app' 20 | include ':quickupload' 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-v23/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/network/BaseNetwork.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.network 2 | 3 | import java.io.IOException 4 | 5 | interface BaseNetwork { 6 | /** 7 | * 为给定的URL和HTTP方法创建一个新的连接。 8 | * @ param uploadId请求此连接的上载的ID 9 | * @ param方法HTTP方法 10 | * @ param url要连接到的URL 11 | * @ return新连接对象 12 | * @ 如果在创建连接对象时发生错误,则抛出IOException 13 | */ 14 | @Throws(IOException::class) 15 | fun createRequest(uploadId: String, method: String, url: String): NetworkRequest 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | local.properties 7 | 8 | # Log/OS Files 9 | *.log 10 | 11 | # Android Studio generated files and folders 12 | captures/ 13 | .externalNativeBuild/ 14 | .cxx/ 15 | *.apk 16 | output.json 17 | 18 | # IntelliJ 19 | *.iml 20 | .idea/ 21 | misc.xml 22 | deploymentTargetDropDown.xml 23 | render.experimental.xml 24 | 25 | # Keystore files 26 | *.jks 27 | *.keystore 28 | 29 | # Google Services (e.g. APIs or Firebase) 30 | google-services.json 31 | 32 | # Android Profiling 33 | *.hprof 34 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/observer/task/UploadTaskObserver.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.observer.task 2 | 3 | import com.dh.quickupload.data.UploadInfo 4 | import com.dh.quickupload.network.ServerResponse 5 | 6 | interface UploadTaskObserver { 7 | fun onWait(info: UploadInfo) 8 | 9 | fun onProgress( 10 | info: UploadInfo 11 | ) 12 | 13 | fun onSuccess( 14 | info: UploadInfo, 15 | response: ServerResponse 16 | ) 17 | 18 | fun onError( 19 | info: UploadInfo, 20 | exception: Throwable 21 | ) 22 | 23 | fun onCompleted( 24 | info: UploadInfo 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/data/RetryPolicyConfig.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.data 2 | 3 | data class RetryPolicyConfig( 4 | /** 5 | * 当上传失败时,设置下一次尝试之前等待的时间 (以秒为单位) 6 | */ 7 | val initialWaitTimeSeconds: Int, 8 | 9 | /** 10 | * 设置两次上传尝试之间的最长等待时间 (以秒为单位)。 11 | */ 12 | val maxWaitTimeSeconds: Int, 13 | 14 | /** 15 | * 设置退避定时器乘数。例如,如果设置为2,则每次上载 16 | */ 17 | val multiplier: Int, 18 | 19 | /** 20 | * 设置每个请求的默认重试次数。 21 | */ 22 | val defaultMaxRetries: Int 23 | ) { 24 | override fun toString(): String { 25 | return """{"initialWaitTimeSeconds": $initialWaitTimeSeconds, "maxWaitTimeSeconds": $maxWaitTimeSeconds, "multiplier": $multiplier, "defaultMaxRetries": $defaultMaxRetries}""" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/dh/updemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.dh.updemo 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.dh.updemo", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/tools/translationfile/SchemeHandler.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.tools.translationfile 2 | 3 | import android.content.Context 4 | import java.io.InputStream 5 | 6 | interface SchemeHandler { 7 | /** 8 | * 使用文件路径初始化实例。 9 | */ 10 | fun init(path: String) 11 | 12 | /** 13 | * 获取文件大小 (以字节为单位)。 14 | */ 15 | fun size(context: Context): Long 16 | 17 | /** 18 | *获取文件输入流以读取它 19 | */ 20 | fun stream(context: Context): InputStream 21 | 22 | /** 23 | * 获取文件内容类型 24 | */ 25 | fun contentType(context: Context): String 26 | 27 | /** 28 | * 获取文件名 29 | */ 30 | fun name(context: Context): String 31 | 32 | /** 33 | * 删除文件 34 | */ 35 | fun delete(context: Context): Boolean 36 | } 37 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/tools/logger/DefaultExt.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.tools.logger 2 | 3 | import android.util.Log 4 | 5 | class DefaultExt : Logger.Ext { 6 | 7 | companion object { 8 | private const val TAG = "QuickUpload" 9 | } 10 | 11 | override fun error(component: String, uploadId: String, message: String, exception: Throwable?) { 12 | Log.e(TAG, "$component - (uploadId: $uploadId) - $message", exception) 13 | } 14 | 15 | override fun debug(component: String, uploadId: String, message: String) { 16 | Log.i(TAG, "$component - (uploadId: $uploadId) - $message") 17 | } 18 | 19 | override fun info(component: String, uploadId: String, message: String) { 20 | Log.i(TAG, "$component - (uploadId: $uploadId) - $message") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /quickupload/src/androidTest/java/com/dh/quickupload/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.dh.quickupload.test", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /quickupload/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/network/okhttp/OkHttpExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.network.okhttp 2 | 3 | import com.dh.quickupload.network.ServerResponse 4 | import okhttp3.Response 5 | 6 | private fun String.requiresRequestBody() = 7 | this == "POST" || this == "PUT" || this == "PATCH" || this == "PROPPATCH" || this == "REPORT" 8 | 9 | private fun String.permitsRequestBody() = !(this == "GET" || this == "HEAD") 10 | 11 | internal fun String.hasBody(): Boolean { 12 | val method = trim().uppercase() 13 | return method.permitsRequestBody() || method.requiresRequestBody() 14 | } 15 | 16 | private fun Response.headersHashMap() = LinkedHashMap(headers.toMap()) 17 | 18 | private fun Response.bodyBytes() = body?.bytes() ?: ByteArray(0) 19 | 20 | internal fun Response.asServerResponse() = ServerResponse(code, bodyBytes(), headersHashMap()) 21 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/network/okhttp/OkHttpBodyWriter.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.network.okhttp 2 | 3 | import com.dh.quickupload.network.BodyWriter 4 | import okio.BufferedSink 5 | import java.io.IOException 6 | 7 | class OkHttpBodyWriter(private val sink: BufferedSink, listener: OnStreamWriteListener) : 8 | BodyWriter(listener) { 9 | @Throws(IOException::class) 10 | override fun internalWrite(bytes: ByteArray) { 11 | sink.write(bytes) 12 | } 13 | 14 | @Throws(IOException::class) 15 | override fun internalWrite(bytes: ByteArray, lengthToWriteFromStart: Int) { 16 | sink.write(bytes, 0, lengthToWriteFromStart) 17 | } 18 | 19 | @Throws(IOException::class) 20 | override fun flush() { 21 | sink.flush() 22 | } 23 | 24 | @Throws(IOException::class) 25 | override fun close() { 26 | sink.close() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /quickupload/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/observer/task/TaskCompletionNotifier.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.observer.task 2 | 3 | import com.dh.quickupload.UploadService 4 | import com.dh.quickupload.data.UploadInfo 5 | import com.dh.quickupload.network.ServerResponse 6 | 7 | class TaskCompletionNotifier(private val service: UploadService) : UploadTaskObserver { 8 | override fun onWait( 9 | info: UploadInfo 10 | ) { 11 | } 12 | 13 | override fun onProgress( 14 | info: UploadInfo 15 | ) { 16 | } 17 | 18 | override fun onSuccess( 19 | info: UploadInfo, 20 | 21 | response: ServerResponse 22 | ) { 23 | } 24 | 25 | override fun onError( 26 | info: UploadInfo, 27 | exception: Throwable 28 | ) { 29 | } 30 | 31 | override fun onCompleted( 32 | info: UploadInfo 33 | ) { 34 | service.taskCompleted(info.uploadId) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /quickupload/src/main/java/com/dh/quickupload/quick/UploadFileExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.dh.quickupload.quick 2 | 3 | import com.dh.quickupload.data.UploadFile 4 | import com.dh.quickupload.extensions.setOrRemove 5 | 6 | //与每个文件关联的属性 7 | private const val PROPERTY_PARAM_NAME = "multipartParamName" 8 | private const val PROPERTY_REMOTE_FILE_NAME = "multipartRemoteFileName" 9 | private const val PROPERTY_CONTENT_TYPE = "multipartContentType" 10 | 11 | internal var UploadFile.parameterName: String? 12 | get() = properties[PROPERTY_PARAM_NAME] 13 | set(value) { 14 | properties.setOrRemove(PROPERTY_PARAM_NAME, value) 15 | } 16 | 17 | internal var UploadFile.remoteFileName: String? 18 | get() = properties[PROPERTY_REMOTE_FILE_NAME] 19 | set(value) { 20 | properties.setOrRemove(PROPERTY_REMOTE_FILE_NAME, value) 21 | } 22 | 23 | internal var UploadFile.contentType: String? 24 | get() = properties[PROPERTY_CONTENT_TYPE] 25 | set(value) { 26 | properties.setOrRemove(PROPERTY_CONTENT_TYPE, value) 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 |