156 lines
5.0 KiB
Kotlin
156 lines
5.0 KiB
Kotlin
/*
|
|
* Nextcloud Android client application
|
|
*
|
|
* @author Chris Narkiewicz
|
|
* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.nextcloud.client.files.downloader
|
|
|
|
import android.app.Service
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.os.IBinder
|
|
import com.nextcloud.client.account.User
|
|
import com.nextcloud.client.core.AsyncRunner
|
|
import com.nextcloud.client.core.LocalBinder
|
|
import com.nextcloud.client.logger.Logger
|
|
import com.nextcloud.client.network.ClientFactory
|
|
import com.nextcloud.client.notifications.AppNotificationManager
|
|
import dagger.android.AndroidInjection
|
|
import javax.inject.Inject
|
|
import javax.inject.Named
|
|
|
|
class DownloaderService : Service() {
|
|
|
|
companion object {
|
|
const val TAG = "DownloaderService"
|
|
const val ACTION_DOWNLOAD = "download"
|
|
const val EXTRA_REQUEST = "request"
|
|
const val EXTRA_USER = "user"
|
|
|
|
fun createBindIntent(context: Context, user: User): Intent {
|
|
return Intent(context, DownloaderService::class.java).apply {
|
|
putExtra(EXTRA_USER, user)
|
|
}
|
|
}
|
|
|
|
fun createDownloadIntent(context: Context, request: Request): Intent {
|
|
return Intent(context, DownloaderService::class.java).apply {
|
|
action = ACTION_DOWNLOAD
|
|
putExtra(EXTRA_REQUEST, request)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Binder forwards [Downloader] API calls to selected instance of downloader.
|
|
*/
|
|
class Binder(
|
|
downloader: DownloaderImpl,
|
|
service: DownloaderService
|
|
) : LocalBinder<DownloaderService>(service),
|
|
Downloader by downloader
|
|
|
|
@Inject
|
|
lateinit var notificationsManager: AppNotificationManager
|
|
|
|
@Inject
|
|
lateinit var clientFactory: ClientFactory
|
|
|
|
@Inject
|
|
@Named("io")
|
|
lateinit var runner: AsyncRunner
|
|
|
|
@Inject
|
|
lateinit var logger: Logger
|
|
|
|
val isRunning: Boolean get() = downloaders.any { it.value.isRunning }
|
|
|
|
private val downloaders: MutableMap<String, DownloaderImpl> = mutableMapOf()
|
|
|
|
override fun onCreate() {
|
|
AndroidInjection.inject(this)
|
|
}
|
|
|
|
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
|
if (intent.action != ACTION_DOWNLOAD) {
|
|
return START_NOT_STICKY
|
|
}
|
|
|
|
if (!isRunning) {
|
|
startForeground(
|
|
AppNotificationManager.DOWNLOAD_NOTIFICATION_ID,
|
|
notificationsManager.buildDownloadServiceForegroundNotification()
|
|
)
|
|
}
|
|
|
|
val request = intent.getParcelableExtra(EXTRA_REQUEST) as Request
|
|
val downloader = getDownloader(request.user)
|
|
downloader.download(request)
|
|
|
|
logger.d(TAG, "Enqueued new download: ${request.uuid} ${request.file.remotePath}")
|
|
|
|
return START_NOT_STICKY
|
|
}
|
|
|
|
override fun onBind(intent: Intent?): IBinder? {
|
|
val user = intent?.getParcelableExtra<User>(EXTRA_USER)
|
|
if (user != null) {
|
|
return Binder(getDownloader(user), this)
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
|
|
private fun onDownloadUpdate(download: Download) {
|
|
if (!isRunning) {
|
|
logger.d(TAG, "All downloads completed")
|
|
notificationsManager.cancelDownloadProgress()
|
|
stopForeground(true)
|
|
stopSelf()
|
|
} else {
|
|
notificationsManager.postDownloadProgress(
|
|
fileOwner = download.request.user,
|
|
file = download.request.file,
|
|
progress = download.progress,
|
|
allowPreview = !download.request.test
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
logger.d(TAG, "Stopping downloader service")
|
|
}
|
|
|
|
private fun getDownloader(user: User): DownloaderImpl {
|
|
val existingDownloader = downloaders[user.accountName]
|
|
return if (existingDownloader != null) {
|
|
existingDownloader
|
|
} else {
|
|
val downloadTaskFactory = DownloadTask.Factory(
|
|
applicationContext,
|
|
{ clientFactory.create(user) },
|
|
contentResolver
|
|
)
|
|
val newDownloader = DownloaderImpl(runner, downloadTaskFactory)
|
|
newDownloader.registerDownloadListener(this::onDownloadUpdate)
|
|
downloaders[user.accountName] = newDownloader
|
|
newDownloader
|
|
}
|
|
}
|
|
}
|