mirror of https://github.com/nextcloud/android
179 lines
6.0 KiB
Kotlin
179 lines
6.0 KiB
Kotlin
/*
|
|
* Nextcloud - Android Client
|
|
*
|
|
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper_ozturk@proton.me>
|
|
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
package com.nextcloud.client.jobs.transfer
|
|
|
|
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.device.PowerManagementService
|
|
import com.nextcloud.client.files.Direction
|
|
import com.nextcloud.client.files.Request
|
|
import com.nextcloud.client.jobs.download.DownloadTask
|
|
import com.nextcloud.client.jobs.upload.UploadTask
|
|
import com.nextcloud.client.logger.Logger
|
|
import com.nextcloud.client.network.ClientFactory
|
|
import com.nextcloud.client.network.ConnectivityService
|
|
import com.nextcloud.client.notifications.AppNotificationManager
|
|
import com.nextcloud.utils.ForegroundServiceHelper
|
|
import com.nextcloud.utils.extensions.getParcelableArgument
|
|
import com.owncloud.android.datamodel.FileDataStorageManager
|
|
import com.owncloud.android.datamodel.ForegroundServiceType
|
|
import com.owncloud.android.datamodel.UploadsStorageManager
|
|
import dagger.android.AndroidInjection
|
|
import javax.inject.Inject
|
|
import javax.inject.Named
|
|
|
|
class FileTransferService : Service() {
|
|
|
|
companion object {
|
|
const val TAG = "DownloaderService"
|
|
const val ACTION_TRANSFER = "transfer"
|
|
const val EXTRA_REQUEST = "request"
|
|
const val EXTRA_USER = "user"
|
|
|
|
fun createBindIntent(context: Context, user: User): Intent {
|
|
return Intent(context, FileTransferService::class.java).apply {
|
|
putExtra(EXTRA_USER, user)
|
|
}
|
|
}
|
|
|
|
fun createTransferRequestIntent(context: Context, request: Request): Intent {
|
|
return Intent(context, FileTransferService::class.java).apply {
|
|
action = ACTION_TRANSFER
|
|
putExtra(EXTRA_REQUEST, request)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Binder forwards [TransferManager] API calls to selected instance of downloader.
|
|
*/
|
|
class Binder(
|
|
downloader: TransferManagerImpl,
|
|
service: FileTransferService
|
|
) : LocalBinder<FileTransferService>(service),
|
|
TransferManager by downloader
|
|
|
|
@Inject
|
|
lateinit var notificationsManager: AppNotificationManager
|
|
|
|
@Inject
|
|
lateinit var clientFactory: ClientFactory
|
|
|
|
@Inject
|
|
@Named("io")
|
|
lateinit var runner: AsyncRunner
|
|
|
|
@Inject
|
|
lateinit var logger: Logger
|
|
|
|
@Inject
|
|
lateinit var uploadsStorageManager: UploadsStorageManager
|
|
|
|
@Inject
|
|
lateinit var connectivityService: ConnectivityService
|
|
|
|
@Inject
|
|
lateinit var powerManagementService: PowerManagementService
|
|
|
|
@Inject
|
|
lateinit var fileDataStorageManager: FileDataStorageManager
|
|
|
|
val isRunning: Boolean get() = downloaders.any { it.value.isRunning }
|
|
|
|
private val downloaders: MutableMap<String, TransferManagerImpl> = mutableMapOf()
|
|
|
|
override fun onCreate() {
|
|
AndroidInjection.inject(this)
|
|
}
|
|
|
|
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
|
if (intent.action != ACTION_TRANSFER) {
|
|
return START_NOT_STICKY
|
|
}
|
|
|
|
if (!isRunning) {
|
|
ForegroundServiceHelper.startService(
|
|
this,
|
|
AppNotificationManager.TRANSFER_NOTIFICATION_ID,
|
|
notificationsManager.buildDownloadServiceForegroundNotification(),
|
|
ForegroundServiceType.DataSync
|
|
)
|
|
}
|
|
|
|
val request: Request = intent.getParcelableArgument(EXTRA_REQUEST, Request::class.java)!!
|
|
val transferManager = getTransferManager(request.user)
|
|
transferManager.enqueue(request)
|
|
|
|
logger.d(TAG, "Enqueued new transfer: ${request.uuid} ${request.file.remotePath}")
|
|
|
|
return START_NOT_STICKY
|
|
}
|
|
|
|
override fun onBind(intent: Intent?): IBinder? {
|
|
val user = intent?.getParcelableArgument(EXTRA_USER, User::class.java) ?: return null
|
|
return Binder(getTransferManager(user), this)
|
|
}
|
|
|
|
private fun onTransferUpdate(transfer: Transfer) {
|
|
if (!isRunning) {
|
|
logger.d(TAG, "All downloads completed")
|
|
notificationsManager.cancelTransferNotification()
|
|
stopForeground(true)
|
|
stopSelf()
|
|
} else if (transfer.direction == Direction.DOWNLOAD) {
|
|
notificationsManager.postDownloadTransferProgress(
|
|
fileOwner = transfer.request.user,
|
|
file = transfer.request.file,
|
|
progress = transfer.progress,
|
|
allowPreview = !transfer.request.test
|
|
)
|
|
} else if (transfer.direction == Direction.UPLOAD) {
|
|
notificationsManager.postUploadTransferProgress(
|
|
fileOwner = transfer.request.user,
|
|
file = transfer.request.file,
|
|
progress = transfer.progress
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun onDestroy() {
|
|
super.onDestroy()
|
|
logger.d(TAG, "Stopping downloader service")
|
|
}
|
|
|
|
private fun getTransferManager(user: User): TransferManagerImpl {
|
|
val existingDownloader = downloaders[user.accountName]
|
|
return if (existingDownloader != null) {
|
|
existingDownloader
|
|
} else {
|
|
val downloadTaskFactory = DownloadTask.Factory(
|
|
applicationContext,
|
|
{ clientFactory.create(user) },
|
|
contentResolver
|
|
)
|
|
val uploadTaskFactory = UploadTask.Factory(
|
|
applicationContext,
|
|
uploadsStorageManager,
|
|
connectivityService,
|
|
powerManagementService,
|
|
{ clientFactory.create(user) },
|
|
fileDataStorageManager
|
|
)
|
|
val newDownloader = TransferManagerImpl(runner, downloadTaskFactory, uploadTaskFactory)
|
|
newDownloader.registerTransferListener(this::onTransferUpdate)
|
|
downloaders[user.accountName] = newDownloader
|
|
newDownloader
|
|
}
|
|
}
|
|
}
|