Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ android {
applicationId "com.boringdroid.systemui"
minSdkVersion 30
targetSdkVersion 34
versionCode 153
versionName "1.5.3"
versionCode 154
versionName "1.5.4"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -152,5 +152,10 @@ dependencies {
implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx
implementation 'com.belerweb:pinyin4j:2.5.1'

implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")


}
26 changes: 26 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- <uses-permission android:name="android.permission.BATTERY_STATS" />-->

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application tools:ignore="AllowBackup,MissingApplicationIcon"
android:usesCleartextTraffic="true"
Expand Down Expand Up @@ -61,6 +64,8 @@
</intent-filter>
</service>

<service android:name=".DownloadService"
android:exported="false"/>
<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
Expand All @@ -69,6 +74,27 @@
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.boringdroid.systemui.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

<!-- <receiver-->
<!-- android:name=".receiver.UpdateActionReceiver"-->
<!-- android:enabled="true"-->
<!-- android:exported="true">-->
<!-- <intent-filter>-->
<!-- <action android:name="com.boringdroid.systemui.ACTION_UPDATE_NOW" />-->
<!-- <action android:name="com.boringdroid.systemui.ACTION_DEFER_UPDATE" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->

</application>

</manifest>
3 changes: 3 additions & 0 deletions app/src/main/aidl/com/boringdroid/systemui/DownloadInfo.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.boringdroid.systemui;

parcelable DownloadInfo;
18 changes: 18 additions & 0 deletions app/src/main/aidl/com/boringdroid/systemui/IDownloadService.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// IDownloadService.aidl
package com.boringdroid.systemui;


import com.boringdroid.systemui.DownloadInfo;
import com.boringdroid.systemui.InterfaceDownloadCallback;

interface IDownloadService {
String startDownload(String url, String fileName);
void pauseDownload(String downloadId);
void resumeDownload(String downloadId);
void cancelDownload(String downloadId);
DownloadInfo getDownloadInfo(String downloadId);
List<DownloadInfo> getAllDownloads();
void registerCallback(InterfaceDownloadCallback callback);
void unregisterCallback(InterfaceDownloadCallback callback);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// InterfaceDownloadCallback.aidl
package com.boringdroid.systemui;

import com.boringdroid.systemui.DownloadInfo;

interface InterfaceDownloadCallback {
void onDownloadProgress(in DownloadInfo info);
void onDownloadComplete(in DownloadInfo info);
void onDownloadFailed(in DownloadInfo info, String error);
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/boringdroid/systemui/DownloadCallback.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.boringdroid.systemui

abstract class DownloadCallback : InterfaceDownloadCallback {
override fun onDownloadProgress(downloadInfo: DownloadInfo) {
// 子类实现
}

override fun onDownloadComplete(downloadInfo: DownloadInfo) {
// 子类实现
}

override fun onDownloadFailed(downloadInfo: DownloadInfo, error: String) {
// 子类实现
}
}
126 changes: 126 additions & 0 deletions app/src/main/java/com/boringdroid/systemui/DownloadInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.boringdroid.systemui


import android.os.Parcel
import android.os.Parcelable

class DownloadInfo : Parcelable {

companion object {
const val STATUS_PENDING:Int = 0
const val STATUS_DOWNLOADING:Int = 1
const val STATUS_PAUSED:Int = 2
const val STATUS_COMPLETED:Int = 3
const val STATUS_FAILED:Int = 4
const val STATUS_CANCELLED:Int = 5

@JvmField
val CREATOR = object : Parcelable.Creator<DownloadInfo> {
override fun createFromParcel(parcel: Parcel): DownloadInfo {
return DownloadInfo(parcel)
}

override fun newArray(size: Int): Array<DownloadInfo?> {
return arrayOfNulls(size)
}
}
}

var url: String = ""
var fileName: String? = null
var downloadId: String = System.currentTimeMillis().toString()
var totalSize: Long = 0L
var downloadedSize: Long = 0L
var status: Int = STATUS_PENDING
var savePath: String = ""
var errorMessage: String? = null

constructor()

constructor(url: String, fileName: String? = null) {
this.url = url
this.fileName = fileName
}

constructor(url: String, fileName: String? = null, downloadId:String, savePath:String, status:Int) {
this.url = url
this.fileName = fileName
this.downloadId = downloadId
this.savePath = savePath
this.status = status

}


constructor(parcel: Parcel) {
url = parcel.readString() ?: ""
fileName = parcel.readString()
downloadId = parcel.readString() ?: System.currentTimeMillis().toString()
totalSize = parcel.readLong()
downloadedSize = parcel.readLong()
status = parcel.readInt()
savePath = parcel.readString() ?: ""
errorMessage = parcel.readString()
}

val progress: Int
get() {
if (totalSize <= 0) return 0
return ((downloadedSize * 100) / totalSize).toInt()
}

fun getFormattedProgress(): String {
val downloadedMB = downloadedSize / 1024.0 / 1024.0
val totalMB = totalSize / 1024.0 / 1024.0
return if (totalSize > 0) {
String.format("%.1fMB / %.1fMB (%d%%)", downloadedMB, totalMB, progress)
} else {
String.format("%.1fMB", downloadedMB)
}
}

fun getStatusText(): String {
return when (status) {
STATUS_DOWNLOADING -> "下载中"
STATUS_PAUSED -> "已暂停"
STATUS_COMPLETED -> "已完成"
STATUS_FAILED -> "失败"
STATUS_CANCELLED -> "已取消"
else -> "等待中"
}
}

fun isDownloading(): Boolean = status == STATUS_DOWNLOADING
fun isPaused(): Boolean = status == STATUS_PAUSED
fun isCompleted(): Boolean = status == STATUS_COMPLETED
fun isFailed(): Boolean = status == STATUS_FAILED
fun isCancelled(): Boolean = status == STATUS_CANCELLED

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(url)
parcel.writeString(fileName)
parcel.writeString(downloadId)
parcel.writeLong(totalSize)
parcel.writeLong(downloadedSize)
parcel.writeInt(status)
parcel.writeString(savePath)
parcel.writeString(errorMessage)
}

override fun describeContents(): Int = 0

override fun toString(): String {
return "DownloadInfo(url='$url', fileName=$fileName, downloadId='$downloadId', " +
"totalSize=$totalSize, downloadedSize=$downloadedSize, status=$status, " +
"savePath='$savePath', errorMessage=$errorMessage), progress=$progress"
}
}

sealed class DownloadStatus(val value: Int) {
val Pending:Int = 0
val DOWNLOADING:Int = 1
val Paused:Int = 2
val Completed:Int = 3
val Failed:Int = 4
val Cancelled:Int = 5
}
90 changes: 90 additions & 0 deletions app/src/main/java/com/boringdroid/systemui/DownloadManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.boringdroid.systemui

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder

object DownloadManager {

private var downloadService: DownloadService? = null
private var isBound = false

private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as DownloadService.DownloadBinder
downloadService = binder.getService()
isBound = true
}

override fun onServiceDisconnected(name: ComponentName?) {
downloadService = null
isBound = false
}
}

fun bindService(context: Context) {
if (!isBound) {
val intent = Intent(context, DownloadService::class.java)
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}

fun unbindService(context: Context) {
if (isBound) {
context.unbindService(serviceConnection)
isBound = false
downloadService = null
}
}

fun startDownload(context: Context, url: String, fileName: String? = null): String? {
return if (isBound) {
downloadService?.startDownload(url, fileName)
} else {
DownloadService.startService(context, url, fileName)
null
}
}

fun pauseDownload(context: Context, downloadId: String) {
if (isBound) {
downloadService?.pauseDownload(downloadId)
} else {
DownloadService.pauseDownload(context, downloadId)
}
}

fun resumeDownload(context: Context, downloadId: String) {
if (isBound) {
downloadService?.resumeDownload(downloadId)
} else {
DownloadService.resumeDownload(context, downloadId)
}
}

fun cancelDownload(context: Context, downloadId: String) {
if (isBound) {
downloadService?.cancelDownload(downloadId)
} else {
DownloadService.cancelDownload(context, downloadId)
}
}

fun getDownloadInfo(downloadId: String): DownloadInfo? {
return downloadService?.getDownloadInfo(downloadId)
}

fun getAllDownloads(): List<DownloadInfo> {
return downloadService?.getAllDownloads() ?: emptyList()
}

fun registerCallback(callback: InterfaceDownloadCallback) {
downloadService?.registerCallback(callback)
}

fun unregisterCallback(callback: InterfaceDownloadCallback) {
downloadService?.unregisterCallback(callback)
}
}
Loading
Loading