├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── DESIGN.md ├── FileDownloader ├── backup │ └── BaseContentProvider.java ├── bintrayUpload.gradle ├── build.gradle ├── proguard-rules.pro ├── project.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── org │ └── wlf │ └── filedownloader │ ├── DownloadCacher.java │ ├── DownloadConfiguration.java │ ├── DownloadFileChangeConfiguration.java │ ├── DownloadFileChangeObserver.java │ ├── DownloadFileInfo.java │ ├── DownloadStatusConfiguration.java │ ├── FileDownloadConfiguration.java │ ├── FileDownloadManager.java │ ├── FileDownloader.java │ ├── base │ ├── BaseDownloadConfigBuilder.java │ ├── BaseUrlFileInfo.java │ ├── Control.java │ ├── FailException.java │ ├── FailReason.java │ ├── Log.java │ ├── Status.java │ ├── Stoppable.java │ └── UrlFailReason.java │ ├── db │ ├── BaseContentDbDao.java │ ├── BaseContentDbHelper.java │ ├── ContentDbDao.java │ └── DatabaseCallback.java │ ├── file_delete │ ├── DeleteDownloadFileTask.java │ ├── DeleteDownloadFilesTask.java │ ├── DownloadDeleteManager.java │ └── DownloadFileDeleter.java │ ├── file_download │ ├── CloseConnectionTask.java │ ├── DetectUrlFileCacher.java │ ├── DetectUrlFileInfo.java │ ├── DetectUrlFileTask.java │ ├── DownloadStatusObserver.java │ ├── DownloadTaskImpl.java │ ├── DownloadTaskManager.java │ ├── FileDownloadTaskParam.java │ ├── HttpConnectionHelper.java │ ├── RetryableDownloadTaskImpl.java │ ├── base │ │ ├── DownloadRecorder.java │ │ ├── DownloadTask.java │ │ ├── HttpFailReason.java │ │ ├── OnStopFileDownloadTaskListener.java │ │ ├── OnTaskRunFinishListener.java │ │ ├── Pauseable.java │ │ └── RetryableDownloadTask.java │ ├── db_recorder │ │ ├── DownloadFileDao.java │ │ ├── DownloadFileDbHelper.java │ │ ├── DownloadFileDbRecorder.java │ │ └── Record.java │ ├── file_saver │ │ ├── DownloadNoticeStrategy.java │ │ ├── FileSaver.java │ │ └── Save.java │ └── http_downloader │ │ ├── ContentLengthInputStream.java │ │ ├── ContentRangeInfo.java │ │ ├── Download.java │ │ ├── HttpDownloader.java │ │ └── Range.java │ ├── file_move │ ├── DownloadFileMover.java │ ├── DownloadMoveManager.java │ ├── MoveDownloadFileTask.java │ └── MoveDownloadFilesTask.java │ ├── file_rename │ ├── DownloadFileRenamer.java │ ├── DownloadRenameManager.java │ └── RenameDownloadFileTask.java │ ├── listener │ ├── OnDeleteDownloadFileListener.java │ ├── OnDeleteDownloadFilesListener.java │ ├── OnDetectBigUrlFileListener.java │ ├── OnDetectUrlFileListener.java │ ├── OnDownloadFileChangeListener.java │ ├── OnFileDownloadStatusListener.java │ ├── OnMoveDownloadFileListener.java │ ├── OnMoveDownloadFilesListener.java │ ├── OnRenameDownloadFileListener.java │ ├── OnRetryableFileDownloadStatusListener.java │ └── simple │ │ └── OnSimpleFileDownloadStatusListener.java │ └── util │ ├── ArrayUtil.java │ ├── CollectionUtil.java │ ├── ContentValuesUtil.java │ ├── DateUtil.java │ ├── DownloadFileUtil.java │ ├── FileUtil.java │ ├── MapUtil.java │ ├── MathUtil.java │ ├── NetworkUtil.java │ └── UrlUtil.java ├── FileDownloaderDemo ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── wlf │ │ └── filedownloader_demo │ │ ├── DownloadFileListAdapter.java │ │ ├── FileDownloadApplication.java │ │ ├── MainActivity.java │ │ └── util │ │ ├── ApkUtil.java │ │ └── TimeUtil.java │ └── res │ ├── layout │ ├── main__activity_main.xml │ └── main__item_download.xml │ ├── menu │ └── options.xml │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── main__ic_apk.png │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ ├── values-w820dp │ ├── dimens.xml │ └── sizes.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── dimens.xml │ ├── sizes.xml │ ├── strings.xml │ └── styles.xml ├── FileDownloaderDemo2 ├── .gitignore ├── build.gradle ├── libs │ ├── LibActionTabPager-release.aar │ └── circleprogressbarlib-0.6.1.aar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── wlf │ │ └── filedownloader_demo2 │ │ ├── FileDownloadApplication.java │ │ ├── MainActivity.java │ │ ├── ToastUtil.java │ │ ├── advanced_use │ │ ├── AdvancedUseActivity.java │ │ ├── course_download │ │ │ ├── CourseDownloadAdapter.java │ │ │ ├── CourseDownloadFragment.java │ │ │ └── TimeUtil.java │ │ ├── course_preview │ │ │ ├── CoursePreviewAdapter.java │ │ │ └── CoursePreviewFragment.java │ │ ├── data_access │ │ │ ├── GetCourseDownloads.java │ │ │ └── GetCoursePreviews.java │ │ ├── db │ │ │ ├── BaseOrmLiteSQLiteHelper.java │ │ │ └── CourseDbHelper.java │ │ └── model │ │ │ └── CoursePreviewInfo.java │ │ └── custom_model │ │ ├── CustomDownloadFileListAdapter.java │ │ ├── CustomModelActivity.java │ │ └── CustomVideoInfo.java │ └── res │ ├── drawable │ ├── advanced_use__selector_btn_bottom_action_tab_1.xml │ └── advanced_use__selector_btn_bottom_action_tab_2.xml │ ├── layout │ ├── advanced_use__activity_advanced_use.xml │ ├── advanced_use__bottom_action_tab.xml │ ├── advanced_use__fragment_course_download.xml │ ├── advanced_use__fragment_course_preview.xml │ ├── advanced_use__item_course_download.xml │ ├── advanced_use__item_course_preview.xml │ ├── custom_model__activity_custom_model.xml │ ├── custom_model__item_download.xml │ └── main__activity_main.xml │ ├── mipmap-hdpi │ ├── advanced_use__btn_bottom_action_tab_1_normal.png │ ├── advanced_use__btn_bottom_action_tab_1_pressed.png │ ├── advanced_use__btn_bottom_action_tab_2_normal.png │ └── advanced_use__btn_bottom_action_tab_2_pressed.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ ├── values-w820dp │ ├── dimens.xml │ └── sizes.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── dimens.xml │ ├── integers.xml │ ├── sizes.xml │ ├── strings.xml │ └── styles.xml ├── LICENSE ├── Q&A-zh.md ├── Q&A.md ├── README-zh.md ├── README.md ├── USEINSERVICE-zh.md ├── USEINSERVICE.md ├── build.gradle ├── capture ├── manager_download.gif ├── manager_download_zh.gif ├── simple_download.gif └── simple_download_zh.gif ├── design ├── Download Process Map.png ├── Download Process Map.vsd ├── file-downloader classes map.png └── file-downloader uml.eap ├── download └── release │ ├── FileDownloader-0.3.2-javadoc │ ├── allclasses-frame.html │ ├── allclasses-noframe.html │ ├── constant-values.html │ ├── deprecated-list.html │ ├── help-doc.html │ ├── index-all.html │ ├── index.html │ ├── org │ │ └── wlf │ │ │ └── filedownloader │ │ │ ├── DownloadCacher.html │ │ │ ├── DownloadConfiguration.Builder.html │ │ │ ├── DownloadConfiguration.MultiBuilder.html │ │ │ ├── DownloadConfiguration.html │ │ │ ├── DownloadFileChangeConfiguration.Builder.html │ │ │ ├── DownloadFileChangeConfiguration.html │ │ │ ├── DownloadFileInfo.Table.html │ │ │ ├── DownloadFileInfo.html │ │ │ ├── DownloadStatusConfiguration.Builder.html │ │ │ ├── DownloadStatusConfiguration.html │ │ │ ├── FileDownloadConfiguration.Builder.html │ │ │ ├── FileDownloadConfiguration.html │ │ │ ├── FileDownloadManager.html │ │ │ ├── FileDownloader.html │ │ │ ├── base │ │ │ ├── BaseDownloadConfigBuilder.html │ │ │ ├── BaseUrlFileInfo.html │ │ │ ├── Control.html │ │ │ ├── FailException.html │ │ │ ├── FailReason.html │ │ │ ├── Log.html │ │ │ ├── Status.html │ │ │ ├── Stoppable.html │ │ │ ├── UrlFailReason.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── db │ │ │ ├── BaseContentDbDao.html │ │ │ ├── BaseContentDbHelper.html │ │ │ ├── ContentDbDao.html │ │ │ ├── DatabaseCallback.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── file_delete │ │ │ ├── DownloadDeleteManager.html │ │ │ ├── DownloadFileDeleter.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── file_download │ │ │ ├── CloseConnectionTask.html │ │ │ ├── DetectUrlFileInfo.html │ │ │ ├── DownloadTaskManager.OnReleaseListener.html │ │ │ ├── DownloadTaskManager.html │ │ │ ├── HttpConnectionHelper.RequestParam.html │ │ │ ├── HttpConnectionHelper.html │ │ │ ├── base │ │ │ │ ├── DownloadRecorder.html │ │ │ │ ├── DownloadTask.html │ │ │ │ ├── HttpFailReason.html │ │ │ │ ├── OnStopFileDownloadTaskListener.StopDownloadFileTaskFailReason.html │ │ │ │ ├── OnStopFileDownloadTaskListener.html │ │ │ │ ├── OnTaskRunFinishListener.html │ │ │ │ ├── Pauseable.html │ │ │ │ ├── RetryableDownloadTask.html │ │ │ │ ├── package-frame.html │ │ │ │ ├── package-summary.html │ │ │ │ └── package-tree.html │ │ │ ├── db_recorder │ │ │ │ ├── DownloadFileDao.html │ │ │ │ ├── DownloadFileDbHelper.html │ │ │ │ ├── DownloadFileDbRecorder.html │ │ │ │ ├── Record.html │ │ │ │ ├── package-frame.html │ │ │ │ ├── package-summary.html │ │ │ │ └── package-tree.html │ │ │ ├── file_saver │ │ │ │ ├── DownloadNoticeStrategy.html │ │ │ │ ├── FileSaver.FileSaveException.html │ │ │ │ ├── FileSaver.OnFileSaveListener.html │ │ │ │ ├── FileSaver.html │ │ │ │ ├── Save.html │ │ │ │ ├── package-frame.html │ │ │ │ ├── package-summary.html │ │ │ │ └── package-tree.html │ │ │ ├── http_downloader │ │ │ │ ├── ContentLengthInputStream.html │ │ │ │ ├── ContentRangeInfo.html │ │ │ │ ├── Download.html │ │ │ │ ├── HttpDownloader.HttpDownloadException.html │ │ │ │ ├── HttpDownloader.OnHttpDownloadListener.html │ │ │ │ ├── HttpDownloader.OnRangeChangeListener.html │ │ │ │ ├── HttpDownloader.html │ │ │ │ ├── Range.html │ │ │ │ ├── package-frame.html │ │ │ │ ├── package-summary.html │ │ │ │ └── package-tree.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── file_move │ │ │ ├── DownloadFileMover.html │ │ │ ├── DownloadMoveManager.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── file_rename │ │ │ ├── DownloadFileRenamer.html │ │ │ ├── DownloadRenameManager.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ │ ├── listener │ │ │ ├── OnDeleteDownloadFileListener.DeleteDownloadFileFailReason.html │ │ │ ├── OnDeleteDownloadFileListener.MainThreadHelper.html │ │ │ ├── OnDeleteDownloadFileListener.OnDeleteDownloadFileFailReason.html │ │ │ ├── OnDeleteDownloadFileListener.html │ │ │ ├── OnDeleteDownloadFilesListener.MainThreadHelper.html │ │ │ ├── OnDeleteDownloadFilesListener.html │ │ │ ├── OnDetectBigUrlFileListener.DetectBigUrlFileFailReason.html │ │ │ ├── OnDetectBigUrlFileListener.MainThreadHelper.html │ │ │ ├── OnDetectBigUrlFileListener.html │ │ │ ├── OnDetectUrlFileListener.DetectUrlFileFailReason.html │ │ │ ├── OnDetectUrlFileListener.html │ │ │ ├── OnDownloadFileChangeListener.MainThreadHelper.html │ │ │ ├── OnDownloadFileChangeListener.Type.html │ │ │ ├── OnDownloadFileChangeListener.html │ │ │ ├── OnFileDownloadStatusListener.FileDownloadStatusFailReason.html │ │ │ ├── OnFileDownloadStatusListener.MainThreadHelper.html │ │ │ ├── OnFileDownloadStatusListener.OnFileDownloadStatusFailReason.html │ │ │ ├── OnFileDownloadStatusListener.html │ │ │ ├── OnMoveDownloadFileListener.MainThreadHelper.html │ │ │ ├── OnMoveDownloadFileListener.MoveDownloadFileFailReason.html │ │ │ ├── OnMoveDownloadFileListener.OnMoveDownloadFileFailReason.html │ │ │ ├── OnMoveDownloadFileListener.html │ │ │ ├── OnMoveDownloadFilesListener.MainThreadHelper.html │ │ │ ├── OnMoveDownloadFilesListener.html │ │ │ ├── OnRenameDownloadFileListener.MainThreadHelper.html │ │ │ ├── OnRenameDownloadFileListener.OnRenameDownloadFileFailReason.html │ │ │ ├── OnRenameDownloadFileListener.RenameDownloadFileFailReason.html │ │ │ ├── OnRenameDownloadFileListener.html │ │ │ ├── OnRetryableFileDownloadStatusListener.MainThreadHelper.html │ │ │ ├── OnRetryableFileDownloadStatusListener.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ ├── package-tree.html │ │ │ └── simple │ │ │ │ ├── OnSimpleFileDownloadStatusListener.html │ │ │ │ ├── package-frame.html │ │ │ │ ├── package-summary.html │ │ │ │ └── package-tree.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ ├── package-tree.html │ │ │ └── util │ │ │ ├── ArrayUtil.html │ │ │ ├── CollectionUtil.html │ │ │ ├── ContentValuesUtil.html │ │ │ ├── DateUtil.html │ │ │ ├── DownloadFileUtil.html │ │ │ ├── FileUtil.html │ │ │ ├── MapUtil.html │ │ │ ├── MathUtil.html │ │ │ ├── NetworkUtil.html │ │ │ ├── UrlUtil.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ ├── overview-frame.html │ ├── overview-summary.html │ ├── overview-tree.html │ ├── package-list │ ├── resources │ │ ├── background.gif │ │ ├── tab.gif │ │ ├── titlebar.gif │ │ └── titlebar_end.gif │ ├── serialized-form.html │ └── stylesheet.css │ └── FileDownloader-0.3.2.jar ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── maven_push.gradle └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=Java 2 | *.css linguist-language=Java 3 | *.html linguist-language=Java -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | 8 | # Android generated 9 | bin/ 10 | gen/ 11 | 12 | # Ant 13 | build.xml 14 | local.properties 15 | 16 | # Maven 17 | target/ 18 | pom.xml.* 19 | release.properties 20 | 21 | # Eclipse 22 | .classpath 23 | .project 24 | .externalToolBuilders/ 25 | 26 | # IntelliJ 27 | *.iml 28 | *.ipr 29 | *.iws 30 | .idea/ 31 | out/ 32 | 33 | # Mac 34 | .DS_Store 35 | 36 | # Ignore gradle files 37 | .gradle/ 38 | build/ -------------------------------------------------------------------------------- /DESIGN.md: -------------------------------------------------------------------------------- 1 | # file-downloader Design 2 | 3 | **Download Process Map** 4 | ![image](https://github.com/wlfcolin/file-downloader/blob/master/design/Download Process Map.png) 5 | 6 | **Classes Map** 7 | ![image](https://github.com/wlfcolin/file-downloader/blob/master/design/file-downloader classes map.png) -------------------------------------------------------------------------------- /FileDownloader/bintrayUpload.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | // load properties 5 | Properties properties = new Properties() 6 | File localPropertiesFile = project.file("local.properties"); 7 | if(localPropertiesFile.exists()){ 8 | properties.load(localPropertiesFile.newDataInputStream()) 9 | } 10 | File projectPropertiesFile = project.file("project.properties"); 11 | if(projectPropertiesFile.exists()){ 12 | properties.load(projectPropertiesFile.newDataInputStream()) 13 | } 14 | 15 | // read properties 16 | def projectName = properties.getProperty("project.name") 17 | def projectGroupId = properties.getProperty("project.groupId") 18 | def projectArtifactId = properties.getProperty("project.artifactId") 19 | def projectVersionName = android.defaultConfig.versionName 20 | def projectPackaging = properties.getProperty("project.packaging") 21 | def projectSiteUrl = properties.getProperty("project.siteUrl") 22 | def projectGitUrl = properties.getProperty("project.gitUrl") 23 | 24 | def developerId = properties.getProperty("developer.id") 25 | def developerName = properties.getProperty("developer.name") 26 | def developerEmail = properties.getProperty("developer.email") 27 | 28 | def bintrayUser = properties.getProperty("bintray.user") 29 | def bintrayApikey = properties.getProperty("bintray.apikey") 30 | 31 | def javadocName = properties.getProperty("javadoc.name") 32 | 33 | group = projectGroupId 34 | 35 | // This generates POM.xml with proper parameters 36 | install { 37 | repositories.mavenInstaller { 38 | pom { 39 | project { 40 | name projectName 41 | groupId projectGroupId 42 | artifactId projectArtifactId 43 | version projectVersionName 44 | packaging projectPackaging 45 | url projectSiteUrl 46 | licenses { 47 | license { 48 | name 'The Apache Software License, Version 2.0' 49 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 50 | } 51 | } 52 | developers { 53 | developer { 54 | id developerId 55 | name developerName 56 | email developerEmail 57 | } 58 | } 59 | scm { 60 | connection projectGitUrl 61 | developerConnection projectGitUrl 62 | url projectSiteUrl 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | // This generates sources.jar 70 | task sourcesJar(type: Jar) { 71 | from android.sourceSets.main.java.srcDirs 72 | classifier = 'sources' 73 | } 74 | 75 | task javadoc(type: Javadoc) { 76 | source = android.sourceSets.main.java.srcDirs 77 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 78 | } 79 | 80 | // This generates javadoc.jar 81 | task javadocJar(type: Jar, dependsOn: javadoc) { 82 | classifier = 'javadoc' 83 | from javadoc.destinationDir 84 | } 85 | 86 | artifacts { 87 | archives javadocJar 88 | archives sourcesJar 89 | } 90 | 91 | // javadoc configuration 92 | javadoc { 93 | options{ 94 | encoding "UTF-8" 95 | charSet 'UTF-8' 96 | author true 97 | version projectVersionName 98 | links "http://docs.oracle.com/javase/7/docs/api" 99 | title javadocName 100 | } 101 | } 102 | 103 | // bintray configuration 104 | bintray { 105 | user = bintrayUser 106 | key = bintrayApikey 107 | configurations = ['archives'] 108 | pkg { 109 | repo = "maven" 110 | name = projectName 111 | websiteUrl = projectSiteUrl 112 | vcsUrl = projectGitUrl 113 | licenses = ["Apache-2.0"] 114 | publish = true 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /FileDownloader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | android { 3 | compileSdkVersion 8 4 | buildToolsVersion "23.0.3" 5 | defaultConfig { 6 | minSdkVersion 8 7 | targetSdkVersion 8 8 | versionCode 7 9 | versionName "0.3.2" 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | } 17 | 18 | // only use by uploading release version to bintray 19 | // apply from: "bintrayUpload.gradle" 20 | // only use by uploading release version to maven center 21 | // apply from: '../maven_push.gradle' 22 | 23 | } 24 | 25 | dependencies { 26 | } 27 | -------------------------------------------------------------------------------- /FileDownloader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\_AndroidTools\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /FileDownloader/project.properties: -------------------------------------------------------------------------------- 1 | #project 2 | project.name=file-downloader 3 | project.groupId=org.wlf 4 | project.artifactId=FileDownloader 5 | project.packaging=aar 6 | project.siteUrl=https://github.com/wlfcolin/file-downloader 7 | project.gitUrl=https://github.com/wlfcolin/file-downloader.git 8 | 9 | #javadoc 10 | javadoc.name=file-downloader -------------------------------------------------------------------------------- /FileDownloader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/DownloadFileChangeConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader; 2 | 3 | import org.wlf.filedownloader.util.CollectionUtil; 4 | import org.wlf.filedownloader.util.UrlUtil; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * DownloadFileChange Configuration 13 | * 14 | * @author wlf(Andy) 15 | * @email 411086563@qq.com 16 | */ 17 | public class DownloadFileChangeConfiguration { 18 | 19 | /** 20 | * Configuration Builder 21 | */ 22 | public static class Builder { 23 | 24 | /** 25 | * all listen urls, default is null which means listen all 26 | */ 27 | private Set mListenUrls; 28 | /** 29 | * whether the callback method is in a single thread, true means the callback method is in a single thread, 30 | * otherwise in main thread, default is false 31 | */ 32 | private boolean mIsThreadCallback = false; 33 | 34 | /** 35 | * add the url for listening 36 | * 37 | * @param url file url 38 | * @return the Builder 39 | */ 40 | public Builder addListenUrl(String url) { 41 | if (UrlUtil.isUrl(url)) { 42 | if (mListenUrls == null) { 43 | mListenUrls = new HashSet(); 44 | } 45 | mListenUrls.add(url); 46 | } 47 | return this; 48 | } 49 | 50 | /** 51 | * add the urls for listening 52 | * 53 | * @param urls file url 54 | * @return the Builder 55 | */ 56 | public Builder addListenUrls(List urls) { 57 | 58 | List needAdd = new ArrayList(); 59 | 60 | for (String url : urls) { 61 | if (!UrlUtil.isUrl(url)) { 62 | continue; 63 | } 64 | needAdd.add(url); 65 | } 66 | 67 | if (!CollectionUtil.isEmpty(needAdd)) { 68 | if (mListenUrls == null) { 69 | mListenUrls = new HashSet(); 70 | } 71 | mListenUrls.addAll(needAdd); 72 | } 73 | return this; 74 | } 75 | 76 | /** 77 | * config whether the caller hope the callback method is sync 78 | * 79 | * @param isThreadCallback true means the callback method is in a single thread, otherwise in main thread, 80 | * default is false 81 | * @return the Builder 82 | */ 83 | public Builder configTreadCallback(boolean isThreadCallback) { 84 | this.mIsThreadCallback = isThreadCallback; 85 | return this; 86 | } 87 | 88 | /** 89 | * build DownloadFileChangeConfiguration 90 | * 91 | * @return the DownloadFileChangeConfiguration 92 | */ 93 | public DownloadFileChangeConfiguration build() { 94 | return new DownloadFileChangeConfiguration(this); 95 | } 96 | 97 | } 98 | 99 | // builder 100 | private Builder mBuilder; 101 | 102 | private DownloadFileChangeConfiguration(Builder builder) { 103 | mBuilder = builder; 104 | } 105 | 106 | /** 107 | * get listen urls 108 | * 109 | * @return listen urls, default is null which means listen all 110 | */ 111 | public Set getListenUrls() { 112 | if (mBuilder == null) { 113 | return null; 114 | } 115 | return mBuilder.mListenUrls; 116 | } 117 | 118 | /** 119 | * whether the callback method is sync 120 | * 121 | * @return true means the callback method is in a single thread, otherwise in main thread, default is false 122 | */ 123 | public boolean isTreadCallback() { 124 | if (mBuilder == null) { 125 | return false; 126 | } 127 | return mBuilder.mIsThreadCallback; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/DownloadStatusConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader; 2 | 3 | import org.wlf.filedownloader.util.CollectionUtil; 4 | import org.wlf.filedownloader.util.UrlUtil; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * DownloadStatus Configuration 13 | * 14 | * @author wlf(Andy) 15 | * @email 411086563@qq.com 16 | */ 17 | public class DownloadStatusConfiguration { 18 | 19 | /** 20 | * Configuration Builder 21 | */ 22 | public static class Builder { 23 | 24 | /** 25 | * all listen urls, default is null which means listen all 26 | */ 27 | private Set mListenUrls; 28 | /** 29 | * whether auto release the listener when the listen url downloads finished, default is false 30 | */ 31 | private boolean mAutoRelease; 32 | 33 | /** 34 | * add the url for listening 35 | * 36 | * @param url file url 37 | * @return the Builder 38 | */ 39 | public Builder addListenUrl(String url) { 40 | if (UrlUtil.isUrl(url)) { 41 | if (mListenUrls == null) { 42 | mListenUrls = new HashSet(); 43 | } 44 | mListenUrls.add(url); 45 | } 46 | return this; 47 | } 48 | 49 | /** 50 | * add the urls for listening 51 | * 52 | * @param urls file url 53 | * @return the Builder 54 | */ 55 | public Builder addListenUrls(List urls) { 56 | 57 | List needAdd = new ArrayList(); 58 | 59 | for (String url : urls) { 60 | if (!UrlUtil.isUrl(url)) { 61 | continue; 62 | } 63 | needAdd.add(url); 64 | } 65 | 66 | if (!CollectionUtil.isEmpty(needAdd)) { 67 | if (mListenUrls == null) { 68 | mListenUrls = new HashSet(); 69 | } 70 | mListenUrls.addAll(needAdd); 71 | } 72 | return this; 73 | } 74 | 75 | /** 76 | * config whether auto release the listener when the listen url downloads finished 77 | * 78 | * @param autoRelease true means will auto release the listener the listen url downloads finished, default is 79 | * false 80 | * @return the Builder 81 | */ 82 | public Builder configAutoRelease(boolean autoRelease) { 83 | this.mAutoRelease = autoRelease; 84 | return this; 85 | } 86 | 87 | /** 88 | * build DownloadStatusConfiguration 89 | * 90 | * @return the DownloadStatusConfiguration 91 | */ 92 | public DownloadStatusConfiguration build() { 93 | return new DownloadStatusConfiguration(this); 94 | } 95 | } 96 | 97 | // builder 98 | private Builder mBuilder; 99 | 100 | private DownloadStatusConfiguration(Builder builder) { 101 | mBuilder = builder; 102 | } 103 | 104 | /** 105 | * get listen urls 106 | * 107 | * @return listen urls 108 | */ 109 | public Set getListenUrls() { 110 | if (mBuilder == null) { 111 | return null; 112 | } 113 | return mBuilder.mListenUrls; 114 | } 115 | 116 | /** 117 | * is auto release the listener when the listen url downloads finished 118 | * 119 | * @return true means auto release, default is false 120 | */ 121 | public boolean isAutoRelease() { 122 | if (mBuilder == null) { 123 | return false; 124 | } 125 | return mBuilder.mAutoRelease; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/BaseDownloadConfigBuilder.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * BaseDownloadConfigBuilder 5 | * 6 | * @author wlf(Andy) 7 | * @datetime 2016-01-27 15:31 GMT+8 8 | * @email 411086563@qq.com 9 | */ 10 | public class BaseDownloadConfigBuilder { 11 | 12 | /** 13 | * max retry download times, max is 10 14 | */ 15 | public static final int MAX_RETRY_DOWNLOAD_TIMES = 10; 16 | /** 17 | * default retry download times, default is 0 18 | */ 19 | public static final int DEFAULT_RETRY_DOWNLOAD_TIMES = 0; 20 | /** 21 | * default connect timeout, default is 15s 22 | */ 23 | public static final int DEFAULT_CONNECT_TIMEOUT = 15 * 1000;// 15s 24 | /** 25 | * default connect timeout, default is 5s 26 | */ 27 | public static final int MIN_CONNECT_TIMEOUT = 5 * 1000;// 5s 28 | /** 29 | * default connect timeout, default is 2min 30 | */ 31 | public static final int MAX_CONNECT_TIMEOUT = 120 * 1000;// 120s 32 | 33 | protected int mRetryDownloadTimes; 34 | protected int mConnectTimeout; 35 | 36 | public BaseDownloadConfigBuilder() { 37 | mRetryDownloadTimes = DEFAULT_RETRY_DOWNLOAD_TIMES; 38 | mConnectTimeout = DEFAULT_CONNECT_TIMEOUT; 39 | } 40 | 41 | /** 42 | * config RetryDownloadTimes 43 | * 44 | * @param retryDownloadTimes DownloadTaskSize at the same time, please set 0 to {@link 45 | * #MAX_RETRY_DOWNLOAD_TIMES}, if not set, default is {@link 46 | * #DEFAULT_RETRY_DOWNLOAD_TIMES}, set 0 means not retry 47 | * @return the builder 48 | */ 49 | public BaseDownloadConfigBuilder configRetryDownloadTimes(int retryDownloadTimes) { 50 | if (retryDownloadTimes >= 0 && retryDownloadTimes <= MAX_RETRY_DOWNLOAD_TIMES) { 51 | this.mRetryDownloadTimes = retryDownloadTimes; 52 | } else if (retryDownloadTimes > MAX_RETRY_DOWNLOAD_TIMES) { 53 | this.mRetryDownloadTimes = MAX_RETRY_DOWNLOAD_TIMES; 54 | } else if (retryDownloadTimes < 0) { 55 | this.mRetryDownloadTimes = 0; 56 | } else { 57 | Log.i(getClass().getSimpleName(), "configRetryDownloadTimes 配置下载失败重试次数失败,retryDownloadTimes:" + 58 | retryDownloadTimes); 59 | } 60 | return this; 61 | } 62 | 63 | 64 | /** 65 | * config connect timeout 66 | * 67 | * @param connectTimeout please set {@link#MIN_CONNECT_TIMEOUT} to {@link#MAX_CONNECT_TIMEOUT}, if not set, 68 | * default is {@link#DEFAULT_CONNECT_TIMEOUT}, millisecond 69 | * @return the builder 70 | */ 71 | public BaseDownloadConfigBuilder configConnectTimeout(int connectTimeout) { 72 | if (connectTimeout >= MIN_CONNECT_TIMEOUT && connectTimeout <= MAX_CONNECT_TIMEOUT) { 73 | mConnectTimeout = connectTimeout; 74 | } else if (connectTimeout > MAX_CONNECT_TIMEOUT) { 75 | mConnectTimeout = MAX_CONNECT_TIMEOUT; 76 | } else if (connectTimeout < MIN_CONNECT_TIMEOUT) { 77 | mConnectTimeout = MIN_CONNECT_TIMEOUT; 78 | } else { 79 | Log.i(getClass().getSimpleName(), "configConnectTimeout 配置连接超时时间失败,connectTimeout:" + connectTimeout); 80 | } 81 | 82 | return this; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/BaseUrlFileInfo.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * BaseUrlFile Info 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2015-11-25 09:58 GMT+8 10 | * @email 411086563@qq.com 11 | */ 12 | public abstract class BaseUrlFileInfo { 13 | 14 | /** 15 | * support range of bytes 16 | */ 17 | public static final String RANGE_TYPE_BYTES = "bytes"; 18 | 19 | /** 20 | * file url 21 | */ 22 | protected String mUrl; 23 | /** 24 | * file total size 25 | */ 26 | protected long mFileSize; 27 | /** 28 | * file eTag 29 | */ 30 | protected String mETag; 31 | /** 32 | * file last modified datetime(in server) 33 | */ 34 | protected String mLastModified; 35 | /** 36 | * accept range type 37 | */ 38 | protected String mAcceptRangeType; 39 | /** 40 | * save file dir 41 | */ 42 | protected String mFileDir; 43 | /** 44 | * save file name 45 | */ 46 | protected String mFileName; 47 | /** 48 | * create download datetime, yyyy-MM-dd HH:mm:ss 49 | */ 50 | protected String mCreateDatetime; 51 | 52 | // getters 53 | 54 | /** 55 | * get file url 56 | * 57 | * @return file url 58 | */ 59 | public String getUrl() { 60 | return mUrl; 61 | } 62 | 63 | /** 64 | * get file size 65 | * 66 | * @return file size 67 | * @deprecated use {@link #getFileSizeLong} instead 68 | */ 69 | @Deprecated 70 | public int getFileSize() { 71 | return (int) mFileSize; 72 | } 73 | 74 | /** 75 | * get file size 76 | * 77 | * @return file size 78 | */ 79 | public long getFileSizeLong() { 80 | return mFileSize; 81 | } 82 | 83 | /** 84 | * get file eTag 85 | * 86 | * @return file eTag 87 | */ 88 | public String getETag() { 89 | return mETag; 90 | } 91 | 92 | /** 93 | * get file last modified datetime(in server) 94 | * 95 | * @return file last modified datetime(in server) 96 | */ 97 | public String getLastModified() { 98 | return mLastModified; 99 | } 100 | 101 | /** 102 | * get accept range type 103 | * 104 | * @return accept range type 105 | */ 106 | public String getAcceptRangeType() { 107 | return mAcceptRangeType; 108 | } 109 | 110 | /** 111 | * get save file dir 112 | * 113 | * @return save file dir 114 | */ 115 | public String getFileDir() { 116 | return mFileDir; 117 | } 118 | 119 | /** 120 | * get save file name 121 | * 122 | * @return save file name 123 | */ 124 | public String getFileName() { 125 | return mFileName; 126 | } 127 | 128 | /** 129 | * get create download datetime 130 | * 131 | * @return create download datetime 132 | */ 133 | public String getCreateDatetime() { 134 | return mCreateDatetime; 135 | } 136 | 137 | // other getters 138 | 139 | /** 140 | * get file path 141 | * 142 | * @return file path 143 | */ 144 | public String getFilePath() { 145 | return getFileDir() + File.separator + mFileName; 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return "BaseUrlFileInfo{" + 151 | "mUrl='" + mUrl + '\'' + 152 | ", mFileSize=" + mFileSize + 153 | ", mETag='" + mETag + '\'' + 154 | ", mLastModified='" + mLastModified + '\'' + 155 | ", mAcceptRangeType='" + mAcceptRangeType + '\'' + 156 | ", mFileDir='" + mFileDir + '\'' + 157 | ", mFileName='" + mFileName + '\'' + 158 | ", mCreateDatetime='" + mCreateDatetime + '\'' + 159 | '}'; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/Control.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * to control an operation 5 | * 6 | * @author wlf(Andy) 7 | * @datetime 2015-12-07 22:00 GMT+8 8 | * @email 411086563@qq.com 9 | */ 10 | public interface Control { 11 | 12 | /** 13 | * stop the operation 14 | */ 15 | void stop(); 16 | 17 | /** 18 | * whether is the operation stopped 19 | * 20 | * @return true means the operation has been stopped 21 | */ 22 | boolean isStopped(); 23 | } 24 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/FailException.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * fail exception, use for sync method call 5 | *
6 | * 失败异常,用于同步调用抛出的异常 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public abstract class FailException extends FailReason { 12 | 13 | public FailException(String type) { 14 | super(type); 15 | } 16 | 17 | public FailException(String detailMessage, String type) { 18 | super(detailMessage, type); 19 | } 20 | 21 | public FailException(String detailMessage, Throwable throwable, String type) { 22 | super(detailMessage, throwable, type); 23 | } 24 | 25 | public FailException(Throwable throwable, String type) { 26 | super(throwable, type); 27 | } 28 | 29 | public FailException(String detailMessage, Throwable throwable) { 30 | super(detailMessage, throwable); 31 | } 32 | 33 | public FailException(Throwable throwable) { 34 | super(throwable); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/Status.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * download file status 5 | *
6 | * 文件下载状态 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public final class Status { 12 | 13 | /** 14 | * UNKNOWN 15 | */ 16 | public static final int DOWNLOAD_STATUS_UNKNOWN = 0; 17 | /** 18 | * WAITING(wait for other task finish,there is no more task place to hold this task) 19 | */ 20 | public static final int DOWNLOAD_STATUS_WAITING = 1; 21 | /** 22 | * PREPARING(prepare to connect the url source) 23 | */ 24 | public static final int DOWNLOAD_STATUS_PREPARING = 2; 25 | /** 26 | * PREPARED(the url source has been connected) 27 | */ 28 | public static final int DOWNLOAD_STATUS_PREPARED = 3; 29 | /** 30 | * DOWNLOADING 31 | */ 32 | public static final int DOWNLOAD_STATUS_DOWNLOADING = 4; 33 | /** 34 | * COMPLETED(the file has been fully downloaded without errors) 35 | */ 36 | public static final int DOWNLOAD_STATUS_COMPLETED = 5; 37 | /** 38 | * PAUSED(the download is paused) 39 | */ 40 | public static final int DOWNLOAD_STATUS_PAUSED = 6; 41 | /** 42 | * ERROR(the download encountered serious error and may not recovery) 43 | */ 44 | public static final int DOWNLOAD_STATUS_ERROR = 7; 45 | /** 46 | * FILE_NOT_EXIST(the file has been started downloading ,but removed or delete unexpected) 47 | */ 48 | public static final int DOWNLOAD_STATUS_FILE_NOT_EXIST = 8; 49 | /** 50 | * RETRYING(retry to re-connect the url source after failed) 51 | */ 52 | public static final int DOWNLOAD_STATUS_RETRYING = 9; 53 | } 54 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/Stoppable.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * interface for those can stop classes 5 | *
6 | * 可停止接口 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public interface Stoppable { 12 | 13 | /** 14 | * stop 15 | */ 16 | void stop(); 17 | 18 | /** 19 | * whether is stopped 20 | * 21 | * @return true means stopped 22 | */ 23 | boolean isStopped(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/base/UrlFailReason.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.base; 2 | 3 | /** 4 | * UrlFailReason 5 | * 6 | * @author wlf(Andy) 7 | * @datetime 2016-01-22 14:07 GMT+8 8 | * @email 411086563@qq.com 9 | */ 10 | public abstract class UrlFailReason extends FailReason { 11 | 12 | /** 13 | * fail url 14 | */ 15 | private String mUrl; 16 | 17 | public UrlFailReason(String url, String type) { 18 | super(type); 19 | init(url); 20 | } 21 | 22 | public UrlFailReason(String url, String detailMessage, String type) { 23 | super(detailMessage, type); 24 | init(url); 25 | } 26 | 27 | public UrlFailReason(String url, String detailMessage, Throwable throwable, String type) { 28 | super(detailMessage, throwable, type); 29 | init(url); 30 | } 31 | 32 | public UrlFailReason(String url, Throwable throwable, String type) { 33 | super(throwable, type); 34 | init(url); 35 | } 36 | 37 | public UrlFailReason(String url, String detailMessage, Throwable throwable) { 38 | super(detailMessage, throwable); 39 | init(url); 40 | } 41 | 42 | public UrlFailReason(String url, Throwable throwable) { 43 | super(throwable); 44 | init(url); 45 | } 46 | 47 | private void init(String url) { 48 | this.mUrl = url; 49 | } 50 | 51 | // --------------------------------------getters & setters-------------------------------------- 52 | 53 | /** 54 | * set url 55 | * 56 | * @param url the url 57 | */ 58 | protected final void setUrl(String url) { 59 | mUrl = url; 60 | } 61 | 62 | /** 63 | * get url 64 | * 65 | * @return the url 66 | */ 67 | public String getUrl() { 68 | return mUrl; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/db/BaseContentDbDao.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.db; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | import android.database.sqlite.SQLiteOpenHelper; 7 | 8 | /** 9 | * base dao impl 10 | *
11 | * 基本的ContentDbDao实现封装 12 | * 13 | * @author wlf(Andy) 14 | * @email 411086563@qq.com 15 | */ 16 | public abstract class BaseContentDbDao implements ContentDbDao, DatabaseCallback { 17 | 18 | /** 19 | * default id field name 20 | */ 21 | public static final String DEFAULT_TABLE_ID_FIELD_NAME = "_id"; 22 | 23 | private SQLiteOpenHelper mDbHelper; 24 | private String mTableName; 25 | private String mTableIdFieldName = DEFAULT_TABLE_ID_FIELD_NAME; 26 | 27 | public BaseContentDbDao(SQLiteOpenHelper dbHelper, String tableName, String tableIdFieldName) { 28 | super(); 29 | this.mDbHelper = dbHelper; 30 | this.mTableName = tableName; 31 | this.mTableIdFieldName = tableIdFieldName; 32 | } 33 | 34 | @Override 35 | public long insert(ContentValues values) { 36 | long id = -1; 37 | SQLiteDatabase database = null; 38 | try { 39 | database = mDbHelper.getWritableDatabase(); 40 | id = database.insert(mTableName, null, values); 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | } finally { 44 | // if (database != null) { 45 | // database.close(); 46 | // } 47 | } 48 | return id; 49 | } 50 | 51 | @Override 52 | public int delete(String selection, String[] selectionArgs) { 53 | int count = -1; 54 | SQLiteDatabase database = null; 55 | try { 56 | database = mDbHelper.getWritableDatabase(); 57 | count = database.delete(mTableName, selection, selectionArgs); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } finally { 61 | // if (database != null) { 62 | // database.close(); 63 | // } 64 | } 65 | return count; 66 | } 67 | 68 | @Override 69 | public int update(ContentValues values, String selection, String[] selectionArgs) { 70 | SQLiteDatabase database = null; 71 | int count = -1; 72 | try { 73 | database = mDbHelper.getWritableDatabase(); 74 | count = database.update(mTableName, values, selection, selectionArgs); 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } finally { 78 | // if (database != null) { 79 | // database.close(); 80 | // } 81 | } 82 | return count; 83 | } 84 | 85 | @Override 86 | public Cursor query(String[] projection, String selection, String[] selectionArgs, String sortOrder) { 87 | SQLiteDatabase database = null; 88 | Cursor cursor = null; 89 | try { 90 | database = mDbHelper.getReadableDatabase(); 91 | cursor = database.query(true, mTableName, null, selection, selectionArgs, null, null, sortOrder, null); 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } finally { 95 | // if (database != null) { 96 | // database.close(); 97 | // } 98 | } 99 | return cursor; 100 | } 101 | 102 | @Override 103 | public String getTableName() { 104 | return mTableName; 105 | } 106 | 107 | @Override 108 | public String getTableIdFieldName() { 109 | return mTableIdFieldName; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/db/BaseContentDbHelper.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.db; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteDatabase.CursorFactory; 6 | import android.database.sqlite.SQLiteOpenHelper; 7 | import android.text.TextUtils; 8 | 9 | import org.wlf.filedownloader.util.CollectionUtil; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collection; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * base SQLiteOpenHelper impl 19 | * 20 | * @author wlf(Andy) 21 | * @email 411086563@qq.com 22 | */ 23 | public abstract class BaseContentDbHelper extends SQLiteOpenHelper { 24 | 25 | /** 26 | * map of dao 27 | */ 28 | private Map mContentDbDaoMap = new HashMap(); 29 | 30 | public BaseContentDbHelper(Context context, String name, CursorFactory factory, int version) { 31 | super(context, name, factory, version); 32 | initContentDbDaoMap(); 33 | } 34 | 35 | /** 36 | * init dao map 37 | */ 38 | private void initContentDbDaoMap() { 39 | 40 | List contentDbDaos = new ArrayList(); 41 | 42 | // config daos 43 | onConfigContentDbDaos(contentDbDaos); 44 | 45 | if (CollectionUtil.isEmpty(contentDbDaos)) { 46 | return; 47 | } 48 | 49 | for (ContentDbDao contentDbDao : contentDbDaos) { 50 | if (contentDbDao == null) { 51 | continue; 52 | } 53 | String tableName = contentDbDao.getTableName(); 54 | 55 | if (TextUtils.isEmpty(tableName)) { 56 | continue; 57 | } 58 | 59 | if (mContentDbDaoMap.containsKey(tableName)) { 60 | continue; 61 | } 62 | 63 | // put dao to map 64 | mContentDbDaoMap.put(tableName, contentDbDao); 65 | } 66 | } 67 | 68 | @Override 69 | public void onCreate(SQLiteDatabase db) { 70 | 71 | Collection contentDbDaos = mContentDbDaoMap.values(); 72 | 73 | if (CollectionUtil.isEmpty(contentDbDaos)) { 74 | return; 75 | } 76 | 77 | for (ContentDbDao contentDbDao : contentDbDaos) { 78 | if (contentDbDao == null) { 79 | continue; 80 | } 81 | // call dao's onCreate 82 | contentDbDao.onCreate(db); 83 | } 84 | } 85 | 86 | @Override 87 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 88 | 89 | Collection contentDbDaos = mContentDbDaoMap.values(); 90 | 91 | if (CollectionUtil.isEmpty(contentDbDaos)) { 92 | return; 93 | } 94 | 95 | for (ContentDbDao contentDbDao : contentDbDaos) { 96 | if (contentDbDao == null) { 97 | continue; 98 | } 99 | // call dao's onUpgrade 100 | contentDbDao.onUpgrade(db, oldVersion, newVersion); 101 | } 102 | } 103 | 104 | /** 105 | * config daos 106 | * 107 | * @param contentDbDaos current daos 108 | */ 109 | protected abstract void onConfigContentDbDaos(List contentDbDaos); 110 | 111 | /** 112 | * get dao by table name 113 | * 114 | * @param tableName table name 115 | * @return the dao for the given table name 116 | */ 117 | public ContentDbDao getContentDbDao(String tableName) { 118 | if (!mContentDbDaoMap.containsKey(tableName)) { 119 | throw new RuntimeException("unregistered database table:" + tableName + " in " + this.getClass() 120 | .getSimpleName()); 121 | } 122 | return mContentDbDaoMap.get(tableName); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/db/ContentDbDao.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.db; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | 6 | /** 7 | * the base dao that can use for ContentProvider and SQLiteOpenHelper 8 | *
9 | * 可以通过ContentProvider和SQLiteOpenHelper操作数据库的Dao接口 10 | * 11 | * @author wlf(Andy) 12 | * @email 411086563@qq.com 13 | */ 14 | public interface ContentDbDao extends DatabaseCallback { 15 | 16 | // CRUD 17 | 18 | /** 19 | * insert 20 | * 21 | * @param values A set of column_name/value pairs to add to the database. 22 | * @return -1 means failed,otherwise return the row id 23 | */ 24 | long insert(ContentValues values); 25 | 26 | /** 27 | * delete 28 | * 29 | * @param selection An optional restriction to apply to rows when deleting. 30 | * @param selectionArgs You may include ?s in selection, which will be replaced by 31 | * the values from selectionArgs, in order that they appear in the selection. 32 | * The values will be bound as Strings. 33 | * @return -1 means failed,The number of rows affected. 34 | */ 35 | int delete(String selection, String[] selectionArgs); 36 | 37 | /** 38 | * update 39 | * 40 | * @param values A Bundle mapping from column names to new column values (NULL is a valid value). 41 | * @param selection An optional filter to match rows to update. 42 | * @param selectionArgs You may include ?s in selection, which will be replaced by 43 | * the values from selectionArgs, in order that they appear in the selection. 44 | * The values will be bound as Strings. 45 | * @return -1 means failed,the number of rows affected. 46 | */ 47 | int update(ContentValues values, String selection, String[] selectionArgs); 48 | 49 | /** 50 | * query 51 | * 52 | * @param projection The list of columns to put into the cursor. If 53 | * null all columns are included. 54 | * @param selection A selection criteria to apply when filtering rows. 55 | * If null then all rows are included. 56 | * @param selectionArgs You may include ?s in selection, which will be replaced by 57 | * the values from selectionArgs, in order that they appear in the selection. 58 | * The values will be bound as Strings. 59 | * @param sortOrder How the rows in the cursor should be sorted. 60 | * If null then the provider is free to define the sort order. 61 | * @return a Cursor or null. 62 | */ 63 | Cursor query(String[] projection, String selection, String[] selectionArgs, String sortOrder); 64 | 65 | // other 66 | 67 | /** 68 | * get table name 69 | * 70 | * @return table name 71 | */ 72 | String getTableName(); 73 | 74 | /** 75 | * get id field name 76 | * 77 | * @return id field name 78 | */ 79 | String getTableIdFieldName(); 80 | } 81 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/db/DatabaseCallback.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.db; 2 | 3 | import android.database.sqlite.SQLiteDatabase; 4 | import android.database.sqlite.SQLiteOpenHelper; 5 | 6 | /** 7 | * database callback, see {@link SQLiteOpenHelper}.onXXXX 8 | * 9 | * @author wlf(Andy) 10 | * @email 411086563@qq.com 11 | */ 12 | public interface DatabaseCallback { 13 | 14 | /** 15 | * the database has been created 16 | * 17 | * @param db SQLiteDatabase 18 | */ 19 | void onCreate(SQLiteDatabase db); 20 | 21 | /** 22 | * the database has been upgraded 23 | * 24 | * @param db SQLiteDatabase 25 | * @param oldVersion oldVersion 26 | * @param newVersion newVersion 27 | */ 28 | void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); 29 | } 30 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_delete/DownloadFileDeleter.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_delete; 2 | 3 | import org.wlf.filedownloader.file_download.db_recorder.DownloadFileDbRecorder; 4 | 5 | /** 6 | * DownloadFileDeleter 7 | *
8 | * 删除下载文件 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | * @since 0.3.0 13 | */ 14 | public interface DownloadFileDeleter extends DownloadFileDbRecorder { 15 | 16 | /** 17 | * delete download file 18 | * 19 | * @param url download url 20 | * @throws Exception any exception during delete 21 | */ 22 | void deleteDownloadFile(String url) throws Exception; 23 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/CloseConnectionTask.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.HttpURLConnection; 6 | 7 | /** 8 | * CloseConnection Task 9 | *
10 | * 连接关闭的任务 11 | * 12 | * @author wlf(Andy) 13 | * @email 411086563@qq.com 14 | */ 15 | public class CloseConnectionTask implements Runnable { 16 | 17 | private HttpURLConnection mURLConnection = null; 18 | private InputStream mInputStream = null; 19 | 20 | public CloseConnectionTask(HttpURLConnection urlConnection, InputStream inputStream) { 21 | mURLConnection = urlConnection; 22 | mInputStream = inputStream; 23 | } 24 | 25 | @Override 26 | public void run() { 27 | // close inputStream 28 | if (mInputStream != null) { 29 | try { 30 | mInputStream.close(); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | // close connection 37 | if (mURLConnection != null) { 38 | mURLConnection.disconnect(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/DetectUrlFileCacher.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.wlf.filedownloader.util.DateUtil; 6 | import org.wlf.filedownloader.util.DownloadFileUtil; 7 | import org.wlf.filedownloader.util.UrlUtil; 8 | 9 | import java.util.Calendar; 10 | import java.util.Date; 11 | import java.util.GregorianCalendar; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /** 16 | * DetectUrlFile Cacher 17 | *
18 | * 探测文件缓存器 19 | * 20 | * @author wlf(Andy) 21 | * @email 411086563@qq.com 22 | */ 23 | class DetectUrlFileCacher { 24 | 25 | // detect file memory cache 26 | private Map mDetectUrlFileInfoMap = new HashMap(); 27 | 28 | private Object mModifyLock = new Object();// modify lock 29 | 30 | /** 31 | * update DetectUrlFile 32 | * 33 | * @param detectUrlFileInfo DetectUrlFile 34 | * @return true means update succeed 35 | */ 36 | public boolean addOrUpdateDetectUrlFile(DetectUrlFileInfo detectUrlFileInfo) { 37 | 38 | if (detectUrlFileInfo == null) { 39 | return false; 40 | } 41 | 42 | String url = detectUrlFileInfo.getUrl(); 43 | 44 | if (!UrlUtil.isUrl(url)) { 45 | return false; 46 | } 47 | 48 | DetectUrlFileInfo urlFileInfo = mDetectUrlFileInfoMap.get(url); 49 | synchronized (mModifyLock) {// lock 50 | if (urlFileInfo != null) { 51 | // update memory cache 52 | urlFileInfo.update(detectUrlFileInfo); 53 | return true; 54 | } else { 55 | // add in memory cache 56 | mDetectUrlFileInfoMap.put(url, detectUrlFileInfo); 57 | return true; 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * remove DetectUrlFile 64 | * 65 | * @param url file url 66 | */ 67 | public void removeDetectUrlFile(String url) { 68 | synchronized (mModifyLock) {// lock 69 | mDetectUrlFileInfoMap.remove(url); 70 | } 71 | } 72 | 73 | /** 74 | * get DetectUrlFile by url 75 | * 76 | * @param url file url 77 | * @return DetectUrlFile 78 | */ 79 | public DetectUrlFileInfo getDetectUrlFile(String url) { 80 | DetectUrlFileInfo detectUrlFileInfo = mDetectUrlFileInfoMap.get(url); 81 | // check and remove 82 | if (DownloadFileUtil.isLegal(detectUrlFileInfo)) { 83 | String createDatetime = detectUrlFileInfo.getCreateDatetime(); 84 | if (!TextUtils.isEmpty(detectUrlFileInfo.getCreateDatetime())) { 85 | // check whether is longer than 24 hours(one day) 86 | Date createDate = DateUtil.string2Date_yyyy_MM_dd_HH_mm_ss(createDatetime); 87 | if (createDate != null) { 88 | GregorianCalendar createDateCalendar = new GregorianCalendar(); 89 | createDateCalendar.setTime(createDate); 90 | 91 | GregorianCalendar curDateCalendar = new GregorianCalendar(); 92 | curDateCalendar.setTime(new Date()); 93 | 94 | createDateCalendar.add(Calendar.DAY_OF_YEAR, 1);// one day, 24 hours 95 | if (curDateCalendar.after(createDateCalendar)) { 96 | // remove the cache 97 | removeDetectUrlFile(detectUrlFileInfo.getUrl()); 98 | detectUrlFileInfo = null; 99 | } 100 | } 101 | } 102 | } 103 | return detectUrlFileInfo; 104 | } 105 | 106 | /** 107 | * release cache 108 | */ 109 | public void release() { 110 | synchronized (mModifyLock) {// lock 111 | mDetectUrlFileInfoMap.clear(); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/DetectUrlFileInfo.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.wlf.filedownloader.base.BaseUrlFileInfo; 6 | import org.wlf.filedownloader.util.DateUtil; 7 | import org.wlf.filedownloader.util.FileUtil; 8 | import org.wlf.filedownloader.util.UrlUtil; 9 | 10 | import java.util.Date; 11 | 12 | /** 13 | * DetectUrlFile Info 14 | *
15 | * 探测到的网络文件信息 16 | * 17 | * @author wlf(Andy) 18 | * @email 411086563@qq.com 19 | */ 20 | public class DetectUrlFileInfo extends BaseUrlFileInfo { 21 | 22 | @SuppressWarnings("unused") 23 | private DetectUrlFileInfo() { 24 | } 25 | 26 | /** 27 | * constructor of DetectUrlFileInfo 28 | * 29 | * @param url file url 30 | * @param fileSize file size 31 | * @param eTag file e tag 32 | * @param lastModified file last modified datetime(in server) 33 | * @param acceptRangeType accept range type 34 | * @param fileDir file dir 35 | * @param fileName file name 36 | */ 37 | DetectUrlFileInfo(String url, long fileSize, String eTag, String lastModified, String acceptRangeType, String 38 | fileDir, String fileName) { 39 | super(); 40 | this.mUrl = url; 41 | this.mFileSize = fileSize; 42 | this.mETag = eTag; 43 | this.mLastModified = lastModified; 44 | this.mAcceptRangeType = acceptRangeType; 45 | this.mFileDir = fileDir; 46 | this.mFileName = fileName; 47 | this.mCreateDatetime = DateUtil.date2String_yyyy_MM_dd_HH_mm_ss(new Date()); 48 | } 49 | 50 | /** 51 | * update DetectUrlFileInfo with new DetectUrlFileInfo 52 | * 53 | * @param detectUrlFileInfo new DetectUrlFileInfo 54 | */ 55 | void update(DetectUrlFileInfo detectUrlFileInfo) { 56 | if (UrlUtil.isUrl(detectUrlFileInfo.mUrl)) { 57 | this.mUrl = detectUrlFileInfo.mUrl; 58 | } 59 | if (detectUrlFileInfo.mFileSize > 0 && detectUrlFileInfo.mFileSize != this.mFileSize) { 60 | this.mFileSize = detectUrlFileInfo.mFileSize; 61 | } 62 | if (!TextUtils.isEmpty(detectUrlFileInfo.mETag)) { 63 | this.mETag = detectUrlFileInfo.mETag; 64 | } 65 | if (!TextUtils.isEmpty(detectUrlFileInfo.mLastModified)) { 66 | this.mLastModified = detectUrlFileInfo.mLastModified; 67 | } 68 | if (!TextUtils.isEmpty(detectUrlFileInfo.mAcceptRangeType)) { 69 | this.mAcceptRangeType = detectUrlFileInfo.mAcceptRangeType; 70 | } 71 | if (FileUtil.isFilePath(detectUrlFileInfo.mFileDir)) { 72 | this.mFileDir = detectUrlFileInfo.mFileDir; 73 | } 74 | if (!TextUtils.isEmpty(detectUrlFileInfo.mFileName)) { 75 | this.mFileName = detectUrlFileInfo.mFileName; 76 | } 77 | if (!TextUtils.isEmpty(detectUrlFileInfo.mCreateDatetime)) { 78 | this.mCreateDatetime = detectUrlFileInfo.mCreateDatetime; 79 | } 80 | } 81 | 82 | void setFileDir(String fileDir) { 83 | this.mFileDir = fileDir; 84 | } 85 | 86 | void setFileName(String fileName) { 87 | this.mFileName = fileName; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/FileDownloadTaskParam.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download; 2 | 3 | import org.wlf.filedownloader.DownloadFileInfo; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * FileDownloadTaskParam 9 | * 10 | * @author wlf(Andy) 11 | * @datetime 2016-01-08 18:50 GMT+8 12 | * @email 411086563@qq.com 13 | */ 14 | class FileDownloadTaskParam { 15 | 16 | /** 17 | * file url 18 | */ 19 | private String mUrl; 20 | /** 21 | * the position of this time to start 22 | */ 23 | private long mStartPosInTotal; 24 | /** 25 | * file total size 26 | */ 27 | private long mFileTotalSize; 28 | /** 29 | * file eTag 30 | */ 31 | private String mETag; 32 | /** 33 | * file last modified datetime(in server) 34 | */ 35 | private String mLastModified; 36 | /** 37 | * AcceptRangeType 38 | */ 39 | private String mAcceptRangeType; 40 | /** 41 | * TempFilePath 42 | */ 43 | private String mTempFilePath; 44 | /** 45 | * SaveFilePath 46 | */ 47 | private String mFilePath; 48 | 49 | private String mRequestMethod = "GET"; 50 | 51 | private Map mHeaders;// custom headers 52 | 53 | public FileDownloadTaskParam(String url, long startPosInTotal, long fileTotalSize, String ETag, String 54 | lastModified, String acceptRangeType, String tempFilePath, String filePath) { 55 | mUrl = url; 56 | mStartPosInTotal = startPosInTotal; 57 | mFileTotalSize = fileTotalSize; 58 | mETag = ETag; 59 | mLastModified = lastModified; 60 | mAcceptRangeType = acceptRangeType; 61 | mTempFilePath = tempFilePath; 62 | mFilePath = filePath; 63 | } 64 | 65 | public static FileDownloadTaskParam createByDownloadFile(DownloadFileInfo downloadFileInfo, String requestMethod, 66 | Map headers) { 67 | 68 | if (downloadFileInfo == null) { 69 | return null; 70 | } 71 | 72 | FileDownloadTaskParam fileDownloadTaskParam = new FileDownloadTaskParam(downloadFileInfo.getUrl(), 73 | downloadFileInfo.getDownloadedSizeLong(), downloadFileInfo.getFileSizeLong(), downloadFileInfo 74 | .getETag(), downloadFileInfo.getLastModified(), downloadFileInfo.getAcceptRangeType(), 75 | downloadFileInfo.getTempFilePath(), downloadFileInfo.getFilePath()); 76 | fileDownloadTaskParam.mRequestMethod = requestMethod; 77 | fileDownloadTaskParam.mHeaders = headers; 78 | 79 | return fileDownloadTaskParam; 80 | } 81 | 82 | // --------------------------------------setters-------------------------------------- 83 | 84 | public void setRequestMethod(String requestMethod) { 85 | mRequestMethod = requestMethod; 86 | } 87 | 88 | public void setHeaders(Map headers) { 89 | mHeaders = headers; 90 | } 91 | 92 | // --------------------------------------getters-------------------------------------- 93 | 94 | public String getUrl() { 95 | return mUrl; 96 | } 97 | 98 | public long getStartPosInTotal() { 99 | return mStartPosInTotal; 100 | } 101 | 102 | public long getFileTotalSize() { 103 | return mFileTotalSize; 104 | } 105 | 106 | public String getETag() { 107 | return mETag; 108 | } 109 | 110 | public String getLastModified() { 111 | return mLastModified; 112 | } 113 | 114 | public String getAcceptRangeType() { 115 | return mAcceptRangeType; 116 | } 117 | 118 | public String getTempFilePath() { 119 | return mTempFilePath; 120 | } 121 | 122 | public String getFilePath() { 123 | return mFilePath; 124 | } 125 | 126 | public String getRequestMethod() { 127 | return mRequestMethod; 128 | } 129 | 130 | public Map getHeaders() { 131 | return mHeaders; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/DownloadRecorder.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | import org.wlf.filedownloader.DownloadFileInfo; 4 | import org.wlf.filedownloader.file_download.DetectUrlFileInfo; 5 | import org.wlf.filedownloader.file_download.db_recorder.DownloadFileDbRecorder; 6 | 7 | /** 8 | * DownloadRecorder 9 | *
10 | * 删除下载文件任务 11 | * 12 | * @author wlf(Andy) 13 | * @email 411086563@qq.com 14 | * @since 0.3.0 15 | */ 16 | public interface DownloadRecorder extends DownloadFileDbRecorder { 17 | 18 | /** 19 | * record download file 20 | * 21 | * @param url file url 22 | * @param deleteMode true means delete all resource 23 | * @throws Exception any exception during record 24 | */ 25 | void resetDownloadFile(String url, boolean deleteMode) throws Exception; 26 | 27 | /** 28 | * reset download size 29 | * 30 | * @param url download url 31 | * @param downloadSize the downloadSize reset to 32 | * @throws Exception any fail exception during recording status 33 | */ 34 | void resetDownloadSize(String url, long downloadSize) throws Exception; 35 | 36 | DownloadFileInfo createDownloadFileInfo(DetectUrlFileInfo detectUrlFileInfo); 37 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/DownloadTask.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | import org.wlf.filedownloader.base.Stoppable; 4 | 5 | /** 6 | * DownloadTask interface 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2016-01-10 00:12 GMT+8 10 | * @email 411086563@qq.com 11 | * @since 0.3.0 12 | */ 13 | public interface DownloadTask extends Runnable, Stoppable { 14 | 15 | /** 16 | * get download url of the task 17 | * 18 | * @return download url 19 | */ 20 | String getUrl(); 21 | 22 | /** 23 | * set StopFileDownloadTaskListener 24 | * 25 | * @param onStopFileDownloadTaskListener OnStopFileDownloadTaskListener 26 | */ 27 | void setOnStopFileDownloadTaskListener(OnStopFileDownloadTaskListener onStopFileDownloadTaskListener); 28 | 29 | /** 30 | * set TaskRunFinishListener 31 | * 32 | * @param onTaskRunFinishListener 33 | */ 34 | void setOnTaskRunFinishListener(OnTaskRunFinishListener onTaskRunFinishListener); 35 | } 36 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/HttpFailReason.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | import org.wlf.filedownloader.base.UrlFailReason; 4 | 5 | import java.net.ConnectException; 6 | import java.net.SocketException; 7 | import java.net.SocketTimeoutException; 8 | import java.net.UnknownHostException; 9 | 10 | /** 11 | * HttpFailReason 12 | * 13 | * @author wlf(Andy) 14 | * @datetime 2015-11-27 11:55 GMT+8 15 | * @email 411086563@qq.com 16 | */ 17 | public class HttpFailReason extends UrlFailReason { 18 | 19 | /** 20 | * network denied 21 | */ 22 | public static final String TYPE_NETWORK_DENIED = HttpFailReason.class.getName() + "_TYPE_NETWORK_DENIED"; 23 | /** 24 | * network timeout 25 | */ 26 | public static final String TYPE_NETWORK_TIMEOUT = HttpFailReason.class.getName() + "_TYPE_NETWORK_TIMEOUT"; 27 | 28 | public HttpFailReason(String url, String detailMessage, String type) { 29 | super(url, detailMessage, type); 30 | } 31 | 32 | public HttpFailReason(String url, Throwable throwable) { 33 | super(url, throwable); 34 | } 35 | 36 | @Override 37 | protected void onInitTypeWithOriginalThrowable(Throwable throwable) { 38 | super.onInitTypeWithOriginalThrowable(throwable); 39 | 40 | if (throwable == null) { 41 | return; 42 | } 43 | 44 | if (throwable instanceof SocketTimeoutException) { 45 | setType(TYPE_NETWORK_TIMEOUT); 46 | } else if (throwable instanceof ConnectException || throwable instanceof UnknownHostException) { 47 | setType(TYPE_NETWORK_DENIED); 48 | } else if (throwable instanceof SocketException) { 49 | setType(TYPE_NETWORK_DENIED); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/OnStopFileDownloadTaskListener.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | import org.wlf.filedownloader.base.FailReason; 4 | import org.wlf.filedownloader.listener.OnFileDownloadStatusListener.FileDownloadStatusFailReason; 5 | 6 | /** 7 | * @author wlf(Andy) 8 | * @datetime 2016-01-08 19:05 GMT+8 9 | * @email 411086563@qq.com 10 | */ 11 | public interface OnStopFileDownloadTaskListener { 12 | 13 | /** 14 | * StopFileDownloadTaskSucceed 15 | * 16 | * @param url file url 17 | */ 18 | void onStopFileDownloadTaskSucceed(String url); 19 | 20 | /** 21 | * StopFileDownloadTaskFailed 22 | * 23 | * @param url file url 24 | * @param failReason fail reason 25 | */ 26 | void onStopFileDownloadTaskFailed(String url, StopDownloadFileTaskFailReason failReason); 27 | 28 | /** 29 | * StopDownloadFileTaskFailReason 30 | */ 31 | public static class StopDownloadFileTaskFailReason extends FileDownloadStatusFailReason { 32 | 33 | /** 34 | * the task has been stopped 35 | */ 36 | public static final String TYPE_TASK_HAS_BEEN_STOPPED = StopDownloadFileTaskFailReason.class.getName() + 37 | "_TYPE_TASK_HAS_BEEN_STOPPED"; 38 | 39 | public StopDownloadFileTaskFailReason(String url, String detailMessage, String type) { 40 | super(url, detailMessage, type); 41 | } 42 | 43 | @Override 44 | protected void onInitTypeWithFailReason(FailReason failReason) { 45 | super.onInitTypeWithFailReason(failReason); 46 | 47 | if (failReason == null) { 48 | return; 49 | } 50 | 51 | // other FailReason exceptions that need cast to StopDownloadFileTaskFailReason 52 | 53 | // cast FileDownloadStatusFailReason 54 | if (failReason instanceof FileDownloadStatusFailReason) { 55 | FileDownloadStatusFailReason fileDownloadStatusFailReason = (FileDownloadStatusFailReason) failReason; 56 | setType(fileDownloadStatusFailReason.getType());// init type 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/OnTaskRunFinishListener.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | /** 4 | * @author wlf(Andy) 5 | * @datetime 2016-03-27 21:00 GMT+8 6 | * @email 411086563@qq.com 7 | */ 8 | public interface OnTaskRunFinishListener { 9 | 10 | /** 11 | * onTaskRunFinish 12 | */ 13 | void onTaskRunFinish(); 14 | } 15 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/Pauseable.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | /** 4 | * Pauseable interface 5 | *
6 | * 可暂停的接口 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2016-01-10 00:44 GMT+8 10 | * @email 411086563@qq.com 11 | * @since 0.3.0 12 | */ 13 | public interface Pauseable { 14 | 15 | /** 16 | * whether is downloading 17 | * 18 | * @param url file url 19 | * @return true means the download task of the url is running 20 | */ 21 | boolean isDownloading(String url); 22 | 23 | /** 24 | * pause a download 25 | * 26 | * @param url file url 27 | * @param onStopFileDownloadTaskListener OnStopFileDownloadTaskListener impl 28 | */ 29 | void pause(String url, OnStopFileDownloadTaskListener onStopFileDownloadTaskListener); 30 | } 31 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/base/RetryableDownloadTask.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.base; 2 | 3 | /** 4 | * RetryableDownloadTask interface 5 | * 6 | * @author wlf(Andy) 7 | * @datetime 2016-01-10 00:17 GMT+8 8 | * @email 411086563@qq.com 9 | * @since 0.3.0 10 | */ 11 | public interface RetryableDownloadTask extends DownloadTask { 12 | 13 | /** 14 | * set RetryDownloadTimes 15 | * 16 | * @param retryDownloadTimes 17 | */ 18 | void setRetryDownloadTimes(int retryDownloadTimes); 19 | } 20 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/db_recorder/DownloadFileDao.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.db_recorder; 2 | 3 | import android.database.sqlite.SQLiteDatabase; 4 | import android.database.sqlite.SQLiteOpenHelper; 5 | 6 | import org.wlf.filedownloader.DownloadFileInfo; 7 | import org.wlf.filedownloader.base.Log; 8 | import org.wlf.filedownloader.db.BaseContentDbDao; 9 | 10 | /** 11 | * DownloadFileDao 12 | *
13 | * 操作下载文件的Dao 14 | * 15 | * @author wlf(Andy) 16 | * @email 411086563@qq.com 17 | */ 18 | public class DownloadFileDao extends BaseContentDbDao { 19 | 20 | private static final String TAG = DownloadFileDao.class.getSimpleName(); 21 | 22 | public DownloadFileDao(SQLiteOpenHelper dbHelper) { 23 | super(dbHelper, DownloadFileInfo.Table.TABLE_NAME_OF_DOWNLOAD_FILE, DownloadFileInfo.Table 24 | .COLUMN_NAME_OF_FIELD_ID); 25 | } 26 | 27 | @Override 28 | public void onCreate(SQLiteDatabase db) { 29 | // create table of DownloadFile 30 | db.execSQL(DownloadFileInfo.Table.getCreateTableSql()); 31 | } 32 | 33 | @Override 34 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 35 | 36 | Log.i(TAG, TAG + ".onUpgrade,oldVersion:" + oldVersion + ",oldVersion:" + newVersion); 37 | 38 | // upgrade to version 2 39 | if (newVersion == 2) { 40 | switch (oldVersion) { 41 | case 1: 42 | // version 1 to 2 43 | updateVersion1To2(db); 44 | break; 45 | } 46 | } 47 | // upgrade to version 3 48 | else if (newVersion == 3) { 49 | switch (oldVersion) { 50 | case 1: 51 | // version 1 to 3 52 | updateVersion1To3(db); 53 | break; 54 | case 2: 55 | // version 2 to 3 56 | updateVersion2To3(db); 57 | break; 58 | } 59 | } 60 | // upgrade to version 4 61 | 62 | } 63 | 64 | // version 1 to 2 65 | private void updateVersion1To2(SQLiteDatabase db) { 66 | db.execSQL(DownloadFileInfo.Table.getUpdateTableVersion1To2Sql()); 67 | } 68 | 69 | // version 2 to 3 70 | private void updateVersion2To3(SQLiteDatabase db) { 71 | db.execSQL(DownloadFileInfo.Table.getUpdateTableVersion2To3Sql()); 72 | } 73 | 74 | // version 1 to 3 75 | private void updateVersion1To3(SQLiteDatabase db) { 76 | db.execSQL(DownloadFileInfo.Table.getUpdateTableVersion1To2Sql()); 77 | db.execSQL(DownloadFileInfo.Table.getUpdateTableVersion2To3Sql()); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/db_recorder/DownloadFileDbHelper.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.db_recorder; 2 | 3 | import android.content.Context; 4 | 5 | import org.wlf.filedownloader.db.BaseContentDbHelper; 6 | import org.wlf.filedownloader.db.ContentDbDao; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * DownloadFile DbHelper 12 | *
13 | * 下载文件数据库操作类 14 | * 15 | * @author wlf(Andy) 16 | * @email 411086563@qq.com 17 | */ 18 | public class DownloadFileDbHelper extends BaseContentDbHelper { 19 | 20 | private static final String DB_NAME = "download_file.db"; 21 | private static final int DB_VERSION = 3; 22 | 23 | public DownloadFileDbHelper(Context context) { 24 | super(context, DB_NAME, null, DB_VERSION); 25 | } 26 | 27 | @Override 28 | protected void onConfigContentDbDaos(List contentDbDaos) { 29 | DownloadFileDao downloadFileDao = new DownloadFileDao(this); 30 | // config DownloadFileDao dao 31 | contentDbDaos.add(downloadFileDao); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/db_recorder/DownloadFileDbRecorder.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.db_recorder; 2 | 3 | import org.wlf.filedownloader.DownloadFileInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * record status for download file 9 | *
10 | * 数据库记录器(记录下载文件状态) 11 | * 12 | * @author wlf(Andy) 13 | * @email 411086563@qq.com 14 | */ 15 | public interface DownloadFileDbRecorder extends Record { 16 | 17 | /** 18 | * get DownloadFile by url 19 | * 20 | * @param url the url 21 | * @return DownloadFile recorded 22 | */ 23 | DownloadFileInfo getDownloadFile(String url); 24 | 25 | /** 26 | * get all DownloadFiles 27 | * 28 | * @return all DownloadFile recorded 29 | */ 30 | List getDownloadFiles(); 31 | } 32 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/db_recorder/Record.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.db_recorder; 2 | 3 | import org.wlf.filedownloader.base.Status; 4 | 5 | /** 6 | * record status 7 | *
8 | * 记录状态接口 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | */ 13 | public interface Record { 14 | 15 | /** 16 | * record status 17 | * 18 | * @param url download url 19 | * @param status record status,ref{@link Status} 20 | * @param increaseSize increased size since last record 21 | * @throws Exception any fail exception during recording status 22 | */ 23 | void recordStatus(String url, int status, int increaseSize) throws Exception; 24 | } 25 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/file_saver/DownloadNoticeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.file_saver; 2 | 3 | /** 4 | * the Strategy use for notify download progress 5 | *
6 | * 更新进度的策略 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2015-11-25 11:40 GMT+8 10 | * @email 411086563@qq.com 11 | */ 12 | public enum DownloadNoticeStrategy { 13 | 14 | NOTICE_AUTO(-1),// notice auto 15 | NOTICE_BY_SIZE(1024 * 1024),// notice by size, 1M(bytes for mValue) 16 | NOTICE_BY_TIME(1000 * 2);// notice by time interval, 2s(milliseconds for mValue) 17 | 18 | private long mValue; 19 | 20 | private DownloadNoticeStrategy(long value) { 21 | this.mValue = value; 22 | } 23 | 24 | public long getValue() { 25 | return mValue; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/file_saver/Save.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.file_saver; 2 | 3 | import org.wlf.filedownloader.file_download.http_downloader.ContentLengthInputStream; 4 | 5 | /** 6 | * save data 7 | *
8 | * 保存接口 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | */ 13 | public interface Save { 14 | 15 | /** 16 | * save data 17 | * 18 | * @param inputStream the inputStream data needed to save 19 | * @param startPosInTotal the start position of inputStream start to save in total data 20 | *

21 | * |(0,totalStart)----|(startPosInTotal,inputStream start)--- 22 | * |(inputStream.length,inputStream end)----|(fileTotalSize,totalEnd) 23 | * @throws Exception any fail exception during saving data 24 | */ 25 | void saveData(ContentLengthInputStream inputStream, long startPosInTotal) throws Exception; 26 | } 27 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/http_downloader/ContentLengthInputStream.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.http_downloader; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | /** 7 | * InputStream wrapper 8 | *
9 | * 对InputStream的包装类 10 | * 11 | * @author wlf(Andy) 12 | * @email 411086563@qq.com 13 | */ 14 | public class ContentLengthInputStream extends InputStream { 15 | 16 | private final InputStream mStream; 17 | private final long mLength; 18 | 19 | public ContentLengthInputStream(InputStream stream, long length) { 20 | this.mStream = stream; 21 | this.mLength = length; 22 | } 23 | 24 | public long getLength() { 25 | return mLength; 26 | } 27 | 28 | @Override 29 | public int available() { 30 | return (int) mLength; 31 | } 32 | 33 | @Override 34 | public void close() throws IOException { 35 | mStream.close(); 36 | } 37 | 38 | @Override 39 | public void mark(int readLimit) { 40 | mStream.mark(readLimit); 41 | } 42 | 43 | @Override 44 | public int read() throws IOException { 45 | return mStream.read(); 46 | } 47 | 48 | @Override 49 | public int read(byte[] buffer) throws IOException { 50 | return mStream.read(buffer); 51 | } 52 | 53 | @Override 54 | public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 55 | return mStream.read(buffer, byteOffset, byteCount); 56 | } 57 | 58 | @Override 59 | public void reset() throws IOException { 60 | mStream.reset(); 61 | } 62 | 63 | @Override 64 | public long skip(long byteCount) throws IOException { 65 | return mStream.skip(byteCount); 66 | } 67 | 68 | @Override 69 | public boolean markSupported() { 70 | return mStream.markSupported(); 71 | } 72 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/http_downloader/ContentRangeInfo.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.http_downloader; 2 | 3 | import android.text.TextUtils; 4 | 5 | /** 6 | * use for http header Content-Range field info 7 | *
8 | * Http响应的头Content-Range字段所包含的信息 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | */ 13 | public class ContentRangeInfo { 14 | 15 | public final String contentType;// public final field 16 | public final long startPos;// public final field 17 | public final long endPos;// public final field 18 | public final long totalLength;// public final field 19 | 20 | private ContentRangeInfo(String contentType, long startPos, long endPos, long totalLength) { 21 | super(); 22 | this.contentType = contentType; 23 | this.startPos = startPos; 24 | this.endPos = endPos; 25 | this.totalLength = totalLength; 26 | } 27 | 28 | /** 29 | * get ContentRangeInfo by contentRange field string 30 | * 31 | * @param contentRangeStr http header contentRange field string 32 | * @return ContentRangeInfo 33 | */ 34 | public static ContentRangeInfo getContentRangeInfo(String contentRangeStr) { 35 | 36 | ContentRangeInfo contentRangeInfo = null; 37 | 38 | String contentType = null; 39 | String rangeStartPos = null; 40 | String rangeEndPos = null; 41 | String totalLength = null; 42 | 43 | if (!TextUtils.isEmpty(contentRangeStr)) { 44 | String[] contentRangeStrArrayTemp = contentRangeStr.split(" "); 45 | if (contentRangeStrArrayTemp != null && contentRangeStrArrayTemp.length >= 2) { 46 | // get contentType 47 | contentType = contentRangeStrArrayTemp[0]; 48 | String contentRangeAndLength = contentRangeStrArrayTemp[1]; 49 | if (!TextUtils.isEmpty(contentRangeAndLength)) { 50 | String[] contentRangeAndLengthArrayTemp = contentRangeAndLength.split("/"); 51 | if (contentRangeAndLengthArrayTemp != null && contentRangeAndLengthArrayTemp.length >= 2) { 52 | String contentRanges = contentRangeAndLengthArrayTemp[0]; 53 | String[] contentRangesArrayTemp = contentRanges.split("-"); 54 | if (contentRangesArrayTemp != null && contentRangesArrayTemp.length >= 2) { 55 | // get rangeStartPos 56 | rangeStartPos = contentRangesArrayTemp[0]; 57 | // get rangeEndPos 58 | rangeEndPos = contentRangesArrayTemp[1]; 59 | } 60 | // get totalLength 61 | totalLength = contentRangeAndLengthArrayTemp[1]; 62 | } 63 | } 64 | } 65 | } 66 | 67 | // create ContentRangeInfo 68 | if (!TextUtils.isEmpty(contentType) && !TextUtils.isEmpty(rangeStartPos) && !TextUtils.isEmpty(rangeEndPos) 69 | && !TextUtils.isEmpty(totalLength)) { 70 | try { 71 | long startPos = Long.parseLong(rangeStartPos); 72 | long endPos = Long.parseLong(rangeEndPos); 73 | long totalLen = Long.parseLong(totalLength); 74 | 75 | contentRangeInfo = new ContentRangeInfo(contentType.trim(), startPos, endPos + 1, totalLen); 76 | } catch (NumberFormatException e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | 81 | return contentRangeInfo; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/http_downloader/Download.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.http_downloader; 2 | 3 | /** 4 | * download 5 | *
6 | * 下载接口 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public interface Download { 12 | 13 | /** 14 | * download 15 | * 16 | * @throws Exception any fail exception during download 17 | */ 18 | void download() throws Exception; 19 | } 20 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_download/http_downloader/Range.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_download.http_downloader; 2 | 3 | /** 4 | * data range 5 | *
6 | * 表示数据范围 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public class Range { 12 | 13 | public final long startPos;// public final field 14 | public final long endPos;// public final field 15 | 16 | public Range(long startPos, long endPos) { 17 | super(); 18 | this.startPos = startPos; 19 | this.endPos = endPos; 20 | } 21 | 22 | public long getLength() { 23 | return endPos - startPos; 24 | } 25 | 26 | /** 27 | * check data range whether legal 28 | * 29 | * @param range data range 30 | * @return true means legal 31 | */ 32 | public static boolean isLegal(Range range) { 33 | if (range != null && range.startPos >= 0 && range.endPos > 0 && range.endPos > range.startPos) { 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | if (o instanceof Range) { 42 | Range other = (Range) o; 43 | if (other.startPos == startPos && other.endPos == endPos) { 44 | return true; 45 | } 46 | } 47 | return false; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "[" + startPos + "," + endPos + "]"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_move/DownloadFileMover.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_move; 2 | 3 | import org.wlf.filedownloader.file_download.db_recorder.DownloadFileDbRecorder; 4 | 5 | /** 6 | * DownloadFileMover 7 | *
8 | * 移动下载文件 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | * @since 0.3.0 13 | */ 14 | public interface DownloadFileMover extends DownloadFileDbRecorder { 15 | 16 | /** 17 | * move download file name 18 | * 19 | * @param url download url 20 | * @param newDirPath new file name 21 | * @throws Exception any exception during move 22 | */ 23 | void moveDownloadFile(String url, String newDirPath) throws Exception; 24 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/file_rename/DownloadFileRenamer.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.file_rename; 2 | 3 | import org.wlf.filedownloader.file_download.db_recorder.DownloadFileDbRecorder; 4 | 5 | /** 6 | * DownloadFileRenamer 7 | *
8 | * 重命名下载文件 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | * @since 0.3.0 13 | */ 14 | public interface DownloadFileRenamer extends DownloadFileDbRecorder { 15 | 16 | /** 17 | * rename download file name 18 | * 19 | * @param url download url 20 | * @param newFileName new file name 21 | * @throws Exception any exception during rename 22 | */ 23 | void renameDownloadFile(String url, String newFileName) throws Exception; 24 | } -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/listener/OnDetectUrlFileListener.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.listener; 2 | 3 | import org.wlf.filedownloader.listener.OnDetectBigUrlFileListener.DetectBigUrlFileFailReason; 4 | 5 | /** 6 | * OnDetectUrlFileListener 7 | *
8 | * 探测网络文件监听器 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | * @deprecated this callback can not detect the url file which bigger than 2G, use {@link 13 | * OnDetectBigUrlFileListener} instead 14 | */ 15 | @Deprecated 16 | public interface OnDetectUrlFileListener { 17 | 18 | /** 19 | * the url file need to create(no database record for this url file) 20 | * 21 | * @param url file url 22 | * @param fileName file name 23 | * @param saveDir saveDir 24 | * @param fileSize fileSize 25 | */ 26 | void onDetectNewDownloadFile(String url, String fileName, String saveDir, int fileSize); 27 | 28 | /** 29 | * the url file exist(it is in database record) 30 | * 31 | * @param url file url 32 | */ 33 | void onDetectUrlFileExist(String url); 34 | 35 | /** 36 | * DetectUrlFileFailed 37 | * 38 | * @param url file url 39 | * @param failReason fail reason 40 | */ 41 | void onDetectUrlFileFailed(String url, DetectUrlFileFailReason failReason); 42 | 43 | /** 44 | * DetectUrlFileFailReason 45 | * 46 | * @deprecated use {@link OnDetectBigUrlFileListener} and {@link 47 | * OnDetectBigUrlFileListener#onDetectUrlFileFailed(String, DetectBigUrlFileFailReason)} instead 48 | */ 49 | @Deprecated 50 | public static class DetectUrlFileFailReason extends OnDetectBigUrlFileListener.DetectBigUrlFileFailReason { 51 | 52 | public DetectUrlFileFailReason(String url, String detailMessage, String type) { 53 | super(url, detailMessage, type); 54 | } 55 | 56 | public DetectUrlFileFailReason(String url, Throwable throwable) { 57 | super(url, throwable); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/listener/OnRetryableFileDownloadStatusListener.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.listener; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | import org.wlf.filedownloader.DownloadFileInfo; 7 | 8 | /** 9 | * OnRetryableFileDownloadStatusListener 10 | *
11 | * 文件下载状态改变监听器 12 | * 13 | * @author wlf(Andy) 14 | * @datetime 2016-01-04 11:30 GMT+8 15 | * @email 411086563@qq.com 16 | */ 17 | public interface OnRetryableFileDownloadStatusListener extends OnFileDownloadStatusListener { 18 | 19 | /** 20 | * retry download 21 | * 22 | * @param downloadFileInfo download file info 23 | * @param retryTimes the times to retry 24 | */ 25 | void onFileDownloadStatusRetrying(DownloadFileInfo downloadFileInfo, int retryTimes); 26 | 27 | /** 28 | * Callback helper for main thread 29 | */ 30 | public static class MainThreadHelper { 31 | /** 32 | * retry download 33 | * 34 | * @param downloadFileInfo download file info 35 | * @param retryTimes the times to retry 36 | */ 37 | public static void onFileDownloadStatusRetrying(final DownloadFileInfo downloadFileInfo, final int 38 | retryTimes, final OnRetryableFileDownloadStatusListener onRetryableFileDownloadStatusListener) { 39 | if (onRetryableFileDownloadStatusListener == null) { 40 | return; 41 | } 42 | Handler handler = new Handler(Looper.getMainLooper()); 43 | handler.post(new Runnable() { 44 | @Override 45 | public void run() { 46 | if (onRetryableFileDownloadStatusListener == null) { 47 | return; 48 | } 49 | onRetryableFileDownloadStatusListener.onFileDownloadStatusRetrying(downloadFileInfo, retryTimes); 50 | } 51 | }); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/listener/simple/OnSimpleFileDownloadStatusListener.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.listener.simple; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.widget.Toast; 6 | 7 | import org.wlf.filedownloader.DownloadFileInfo; 8 | import org.wlf.filedownloader.FileDownloadConfiguration; 9 | import org.wlf.filedownloader.FileDownloader; 10 | import org.wlf.filedownloader.listener.OnRetryableFileDownloadStatusListener; 11 | 12 | /** 13 | * OnSimpleFileDownloadStatus Listener 14 | * 15 | * @author wlf(Andy) 16 | * @email 411086563@qq.com 17 | */ 18 | public abstract class OnSimpleFileDownloadStatusListener implements OnRetryableFileDownloadStatusListener { 19 | 20 | @Override 21 | public void onFileDownloadStatusRetrying(DownloadFileInfo downloadFileInfo, int retryTimes) { 22 | } 23 | 24 | @Override 25 | public void onFileDownloadStatusWaiting(DownloadFileInfo downloadFileInfo) { 26 | } 27 | 28 | @Override 29 | public void onFileDownloadStatusPreparing(DownloadFileInfo downloadFileInfo) { 30 | } 31 | 32 | @Override 33 | public void onFileDownloadStatusPrepared(DownloadFileInfo downloadFileInfo) { 34 | } 35 | 36 | @Override 37 | public void onFileDownloadStatusDownloading(DownloadFileInfo downloadFileInfo, float downloadSpeed, long 38 | remainingTime) { 39 | } 40 | 41 | @Override 42 | public void onFileDownloadStatusPaused(DownloadFileInfo downloadFileInfo) { 43 | } 44 | 45 | @Override 46 | public void onFileDownloadStatusCompleted(DownloadFileInfo downloadFileInfo) { 47 | // child should override recommend, if not, it will make a toast below 48 | Context appContext = getAppContext(); 49 | if (appContext != null) { 50 | String fileName = downloadFileInfo != null ? downloadFileInfo.getFileName() : null; 51 | if (!TextUtils.isEmpty(fileName)) { 52 | Toast.makeText(appContext, "Download " + fileName + " completed !", Toast.LENGTH_SHORT).show(); 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | public void onFileDownloadStatusFailed(String url, DownloadFileInfo downloadFileInfo, 59 | FileDownloadStatusFailReason failReason) { 60 | // child should override recommend, if not, it will make a toast below 61 | Context appContext = getAppContext(); 62 | if (appContext != null) { 63 | String fileName = downloadFileInfo != null ? downloadFileInfo.getFileName() : null; 64 | if (!TextUtils.isEmpty(fileName)) { 65 | Toast.makeText(appContext, "Download " + fileName + " error !", Toast.LENGTH_SHORT).show(); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * get AppContext 72 | */ 73 | private Context getAppContext() { 74 | 75 | Context appContext = null; 76 | 77 | if (FileDownloader.isInit()) { 78 | FileDownloadConfiguration configuration = FileDownloader.getFileDownloadConfiguration(); 79 | appContext = configuration != null ? configuration.getContext() : null; 80 | } 81 | return appContext; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/ArrayUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | /** 4 | * Util for Array 5 | * 6 | * @author wlf(Andy) 7 | * @email 411086563@qq.com 8 | */ 9 | public class ArrayUtil { 10 | 11 | /** 12 | * Returns true if the array is null or 0-length. 13 | * 14 | * @param array the array to be examined 15 | * @return true if array is null or zero length 16 | */ 17 | public static boolean isEmpty(Object[] array) { 18 | if (array == null || array.length == 0) { 19 | return true; 20 | } else { 21 | return false; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/CollectionUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * Util for {@link Collection} 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public class CollectionUtil { 12 | 13 | /** 14 | * Returns true if the collection is null or 0-length. 15 | * 16 | * @param collection the collection to be examined 17 | * @return true if str collection null or zero length 18 | */ 19 | public static boolean isEmpty(Collection collection) { 20 | if (collection == null || collection.isEmpty() || collection.size() == 0) { 21 | return true; 22 | } else { 23 | return false; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/ContentValuesUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | import android.content.ContentValues; 4 | 5 | /** 6 | * Util for {@link ContentValues} 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2015-11-14 17:53 GMT+8 10 | * @email 411086563@qq.com 11 | */ 12 | public class ContentValuesUtil { 13 | 14 | /** 15 | * Returns true if the values is null or 0-length. 16 | * 17 | * @param values the values to be examined 18 | * @return true if values is null or zero length 19 | */ 20 | public static boolean isEmpty(ContentValues values) { 21 | if (values == null || values.size() == 0) { 22 | return true; 23 | } else { 24 | return false; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.text.ParseException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.Locale; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * Util for formatting {@link Date} 14 | * 15 | * @author wlf(Andy) 16 | * @datetime 2015-12-30 23:53 GMT+8 17 | * @email 411086563@qq.com 18 | */ 19 | public class DateUtil { 20 | 21 | /** 22 | * Thread Safe SimpleDateFormats 23 | */ 24 | private static final Map> DATE_FORMAT_MAP = new ConcurrentHashMap>(); 26 | 27 | /** 28 | * get a safe SimpleDateFormat 29 | * 30 | * @param format date format in string 31 | * @return SimpleDateFormat 32 | */ 33 | private static SimpleDateFormat getSimpleDateFormat(String format) { 34 | ThreadLocal threadLocal = DATE_FORMAT_MAP.get(format); 35 | if (threadLocal == null) { 36 | threadLocal = new ThreadLocal(); 37 | DATE_FORMAT_MAP.put(format, threadLocal); 38 | } 39 | SimpleDateFormat sdf = threadLocal.get(); 40 | if (sdf == null) { 41 | sdf = new SimpleDateFormat(format, Locale.getDefault()); 42 | threadLocal.set(sdf); 43 | } 44 | return sdf; 45 | } 46 | 47 | /** 48 | * get datetime by date string which formatted with yyyy-MM-dd HH:mm:ss 49 | * 50 | * @param strDate formatted with yyyy-MM-dd HH:mm:ss 51 | * @return date object 52 | */ 53 | public static Date string2Date_yyyy_MM_dd_HH_mm_ss(String strDate) { 54 | 55 | if (TextUtils.isEmpty(strDate)) { 56 | return null; 57 | } 58 | 59 | SimpleDateFormat sdf = getSimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 60 | try { 61 | return sdf.parse(strDate); 62 | } catch (ParseException e) { 63 | e.printStackTrace(); 64 | } 65 | return null; 66 | } 67 | 68 | /** 69 | * format date to yyyy-MM-dd HH:mm:ss string 70 | * 71 | * @param date the date 72 | * @return formatted string 73 | */ 74 | public static String date2String_yyyy_MM_dd_HH_mm_ss(Date date) { 75 | return getSimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/MapUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Util for {@link Map} 7 | * 8 | * @author wlf(Andy) 9 | * @datetime 2015-11-14 18:12 GMT+8 10 | * @email 411086563@qq.com 11 | */ 12 | public class MapUtil { 13 | 14 | /** 15 | * Returns true if the collection is null or 0-length. 16 | * 17 | * @param map the map to be examined 18 | * @return true if str is null or zero length 19 | */ 20 | public static boolean isEmpty(Map map) { 21 | if (map == null || map.isEmpty() || map.size() == 0) { 22 | return true; 23 | } else { 24 | return false; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/MathUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | /** 4 | * MathUtil 5 | * 6 | * @author wlf(Andy) 7 | * @datetime 2015-12-11 21:40 GMT+8 8 | * @email 411086563@qq.com 9 | */ 10 | public class MathUtil { 11 | 12 | public static double formatNumber(double number) { 13 | return (Math.round(number * 100.00)) / 100.00; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /FileDownloader/src/main/java/org/wlf/filedownloader/util/NetworkUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader.util; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * NetworkUtil 9 | * 10 | * @author wlf(Andy) 11 | * @email 411086563@qq.com 12 | */ 13 | public class NetworkUtil { 14 | 15 | /** 16 | * is network available 17 | * 18 | * @param context Context 19 | * @return true means network is available 20 | */ 21 | public static boolean isNetworkAvailable(Context context) { 22 | boolean isNetwork = false; 23 | ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 24 | if (connectivity == null) { 25 | return isNetwork; 26 | } else { 27 | NetworkInfo[] info = connectivity.getAllNetworkInfo(); 28 | if (info != null) { 29 | for (int i = 0; i < info.length; i++) { 30 | if (info[i].getState() == NetworkInfo.State.CONNECTED) { 31 | isNetwork = true; 32 | break; 33 | } 34 | } 35 | } 36 | return isNetwork; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /FileDownloaderDemo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 15 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "org.wlf.filedownloader_demo" 9 | minSdkVersion 8 10 | targetSdkVersion 15 11 | versionCode 7 12 | versionName "0.3.2" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile project(':FileDownloader') 25 | // compile 'org.wlf:FileDownloader:0.3.2' 26 | } 27 | -------------------------------------------------------------------------------- /FileDownloaderDemo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\_AndroidTools\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /FileDownloaderDemo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /FileDownloaderDemo/src/main/java/org/wlf/filedownloader_demo/FileDownloadApplication.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader_demo; 2 | 3 | import android.app.Application; 4 | import android.os.Environment; 5 | 6 | import org.wlf.filedownloader.FileDownloadConfiguration; 7 | import org.wlf.filedownloader.FileDownloadConfiguration.Builder; 8 | import org.wlf.filedownloader.FileDownloader; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * Demo Test Application 14 | *
15 | * 测试应用的Application 16 | * 17 | * @author wlf(Andy) 18 | * @email 411086563@qq.com 19 | */ 20 | public class FileDownloadApplication extends Application { 21 | 22 | @Override 23 | public void onCreate() { 24 | super.onCreate(); 25 | 26 | // init FileDownloader 27 | initFileDownloader(); 28 | } 29 | 30 | @Override 31 | public void onTerminate() { 32 | super.onTerminate(); 33 | 34 | // release FileDownloader 35 | releaseFileDownloader(); 36 | } 37 | 38 | // init FileDownloader 39 | private void initFileDownloader() { 40 | 41 | // 1.create FileDownloadConfiguration.Builder 42 | Builder builder = new FileDownloadConfiguration.Builder(this); 43 | 44 | // 2.config FileDownloadConfiguration.Builder 45 | builder.configFileDownloadDir(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + 46 | "FileDownloader"); // config the download path 47 | // builder.configFileDownloadDir("/storage/sdcard1/FileDownloader"); 48 | 49 | // allow 3 download tasks at the same time 50 | builder.configDownloadTaskSize(3); 51 | 52 | // config retry download times when failed 53 | builder.configRetryDownloadTimes(5); 54 | 55 | // enable debug mode 56 | //builder.configDebugMode(true); 57 | 58 | // config connect timeout 59 | builder.configConnectTimeout(25000); // 25s 60 | 61 | // 3.init FileDownloader with the configuration 62 | FileDownloadConfiguration configuration = builder.build(); // build FileDownloadConfiguration with the builder 63 | FileDownloader.init(configuration); 64 | } 65 | 66 | // release FileDownloader 67 | private void releaseFileDownloader() { 68 | FileDownloader.release(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /FileDownloaderDemo/src/main/java/org/wlf/filedownloader_demo/util/ApkUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader_demo.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.ApplicationInfo; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.content.pm.PackageManager.NameNotFoundException; 9 | import android.net.Uri; 10 | import android.text.TextUtils; 11 | 12 | import java.io.File; 13 | 14 | /** 15 | * apk util 16 | *
17 | * Apk文件操作相关工具类 18 | * 19 | * @author wlf(Andy) 20 | * @email 411086563@qq.com 21 | */ 22 | public class ApkUtil { 23 | 24 | /** 25 | * get UnInstallApkPackageName 26 | * 27 | * @param context Context 28 | * @param apkPath apkPath 29 | * @return apk PackageName 30 | */ 31 | public static String getUnInstallApkPackageName(Context context, String apkPath) { 32 | PackageManager pm = context.getPackageManager(); 33 | PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); 34 | if (info != null) { 35 | ApplicationInfo appInfo = info.applicationInfo; 36 | if (appInfo != null) { 37 | return appInfo.packageName; 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | /** 44 | * install an apk bu apkPath 45 | * 46 | * @param context Context 47 | * @param apkPath apkPath 48 | */ 49 | public static final void installApk(Context context, String apkPath) { 50 | if (TextUtils.isEmpty(apkPath)) { 51 | return; 52 | } 53 | Intent intent = new Intent(Intent.ACTION_VIEW); 54 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 55 | intent.setDataAndType(Uri.fromFile(new File(apkPath)), "application/vnd.android.package-archive"); 56 | context.startActivity(intent); 57 | } 58 | 59 | /** 60 | * check whether app installed 61 | * 62 | * @param context 63 | * @param packageName 64 | * @return 65 | */ 66 | public static boolean checkAppInstalled(Context context, String packageName) { 67 | if (TextUtils.isEmpty(packageName)) { 68 | return false; 69 | } 70 | try { 71 | context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_INSTRUMENTATION); 72 | return true; 73 | } catch (NameNotFoundException e) { 74 | return false; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /FileDownloaderDemo/src/main/java/org/wlf/filedownloader_demo/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package org.wlf.filedownloader_demo.util; 2 | 3 | /** 4 | * time util 5 | *
6 | * 时间工具类 7 | * 8 | * @author wlf(Andy) 9 | * @email 411086563@qq.com 10 | */ 11 | public class TimeUtil { 12 | 13 | /** 14 | * format seconds to HH:mm:ss String 15 | * 16 | * @param seconds seconds 17 | * @return String of formatted in HH:mm:ss 18 | */ 19 | public static String seconds2HH_mm_ss(long seconds) { 20 | 21 | long h = 0; 22 | long m = 0; 23 | long s = 0; 24 | long temp = seconds % 3600; 25 | 26 | if (seconds > 3600) { 27 | h = seconds / 3600; 28 | if (temp != 0) { 29 | if (temp > 60) { 30 | m = temp / 60; 31 | if (temp % 60 != 0) { 32 | s = temp % 60; 33 | } 34 | } else { 35 | s = temp; 36 | } 37 | } 38 | } else { 39 | m = seconds / 60; 40 | if (seconds % 60 != 0) { 41 | s = seconds % 60; 42 | } 43 | } 44 | 45 | String dh = h < 10 ? "0" + h : h + ""; 46 | String dm = m < 10 ? "0" + m : m + ""; 47 | String ds = s < 10 ? "0" + s : s + ""; 48 | 49 | return dh + ":" + dm + ":" + ds; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /FileDownloaderDemo/src/main/res/layout/main__activity_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 18 | 19 |