File Operations Notification
This commit is contained in:
parent
754ef3bc5a
commit
f00901a717
@ -1,6 +1,10 @@
|
|||||||
package sushi.hardcore.droidfs
|
package sushi.hardcore.droidfs
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.*
|
import android.os.*
|
||||||
@ -13,10 +17,16 @@ import sushi.hardcore.droidfs.util.Wiper
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
|
|
||||||
class FileOperationService : Service() {
|
class FileOperationService : Service() {
|
||||||
|
companion object {
|
||||||
|
const val NOTIFICATION_ID = 1
|
||||||
|
const val NOTIFICATION_CHANNEL_ID = "FileOperations"
|
||||||
|
}
|
||||||
|
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
private lateinit var gocryptfsVolume: GocryptfsVolume
|
private lateinit var gocryptfsVolume: GocryptfsVolume
|
||||||
|
private lateinit var notificationManager: NotificationManager
|
||||||
|
|
||||||
inner class LocalBinder : Binder() {
|
inner class LocalBinder : Binder() {
|
||||||
fun getService(): FileOperationService = this@FileOperationService
|
fun getService(): FileOperationService = this@FileOperationService
|
||||||
@ -29,6 +39,35 @@ class FileOperationService : Service() {
|
|||||||
return binder
|
return binder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showNotification(message: String, total: Int): Notification.Builder {
|
||||||
|
if (!::notificationManager.isInitialized){
|
||||||
|
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
}
|
||||||
|
val notificationBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, getString(R.string.file_operations), NotificationManager.IMPORTANCE_LOW)
|
||||||
|
notificationManager.createNotificationChannel(channel)
|
||||||
|
Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||||
|
} else {
|
||||||
|
Notification.Builder(this)
|
||||||
|
}
|
||||||
|
notificationBuilder.setOngoing(true)
|
||||||
|
.setContentTitle(getString(R.string.file_op_notification_title))
|
||||||
|
.setContentText(message)
|
||||||
|
.setSmallIcon(R.mipmap.icon_launcher)
|
||||||
|
.setProgress(total, 0, false)
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
|
||||||
|
return notificationBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNotificationProgress(notificationBuilder: Notification.Builder, progress: Int, total: Int){
|
||||||
|
notificationBuilder.setProgress(total, progress, false)
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelNotification(){
|
||||||
|
notificationManager.cancel(NOTIFICATION_ID)
|
||||||
|
}
|
||||||
|
|
||||||
private fun copyFile(srcPath: String, dstPath: String, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume): Boolean {
|
private fun copyFile(srcPath: String, dstPath: String, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume): Boolean {
|
||||||
var success = true
|
var success = true
|
||||||
val srcHandleId = remoteGocryptfsVolume.openReadMode(srcPath)
|
val srcHandleId = remoteGocryptfsVolume.openReadMode(srcPath)
|
||||||
@ -60,55 +99,66 @@ class FileOperationService : Service() {
|
|||||||
|
|
||||||
fun copyElements(items: ArrayList<OperationFile>, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume, callback: (String?) -> Unit){
|
fun copyElements(items: ArrayList<OperationFile>, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume, callback: (String?) -> Unit){
|
||||||
Thread {
|
Thread {
|
||||||
|
val notificationBuilder = showNotification(getString(R.string.file_op_copy_msg), items.size)
|
||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
for (item in items){
|
for (i in 0 until items.size){
|
||||||
if (item.explorerElement.isDirectory){
|
if (items[i].explorerElement.isDirectory){
|
||||||
if (!gocryptfsVolume.pathExists(item.dstPath!!)) {
|
if (!gocryptfsVolume.pathExists(items[i].dstPath!!)) {
|
||||||
if (!gocryptfsVolume.mkdir(item.dstPath!!)) {
|
if (!gocryptfsVolume.mkdir(items[i].dstPath!!)) {
|
||||||
failedItem = item.explorerElement.fullPath
|
failedItem = items[i].explorerElement.fullPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!copyFile(item.explorerElement.fullPath, item.dstPath!!, remoteGocryptfsVolume)){
|
if (!copyFile(items[i].explorerElement.fullPath, items[i].dstPath!!, remoteGocryptfsVolume)){
|
||||||
failedItem = item.explorerElement.fullPath
|
failedItem = items[i].explorerElement.fullPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedItem != null){
|
if (failedItem == null){
|
||||||
|
updateNotificationProgress(notificationBuilder, i, items.size)
|
||||||
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cancelNotification()
|
||||||
callback(failedItem)
|
callback(failedItem)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveElements(items: ArrayList<OperationFile>, callback: (String?) -> Unit){
|
fun moveElements(items: ArrayList<OperationFile>, callback: (String?) -> Unit){
|
||||||
Thread {
|
Thread {
|
||||||
|
val notificationBuilder = showNotification(getString(R.string.file_op_move_msg), items.size)
|
||||||
val mergedFolders = ArrayList<String>()
|
val mergedFolders = ArrayList<String>()
|
||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
for (item in items){
|
for (i in 0 until items.size){
|
||||||
if (item.explorerElement.isDirectory && gocryptfsVolume.pathExists(item.dstPath!!)){ //folder will be merged
|
if (items[i].explorerElement.isDirectory && gocryptfsVolume.pathExists(items[i].dstPath!!)){ //folder will be merged
|
||||||
mergedFolders.add(item.explorerElement.fullPath)
|
mergedFolders.add(items[i].explorerElement.fullPath)
|
||||||
} else {
|
} else {
|
||||||
if (!gocryptfsVolume.rename(item.explorerElement.fullPath, item.dstPath!!)){
|
if (!gocryptfsVolume.rename(items[i].explorerElement.fullPath, items[i].dstPath!!)){
|
||||||
failedItem = item.explorerElement.fullPath
|
failedItem = items[i].explorerElement.fullPath
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
updateNotificationProgress(notificationBuilder, i, items.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedItem == null){
|
if (failedItem == null){
|
||||||
for (path in mergedFolders) {
|
for (i in 0 until mergedFolders.size) {
|
||||||
if (!gocryptfsVolume.rmdir(path)){
|
if (!gocryptfsVolume.rmdir(mergedFolders[i])){
|
||||||
failedItem = path
|
failedItem = mergedFolders[i]
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
updateNotificationProgress(notificationBuilder, items.size-(mergedFolders.size-i), items.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cancelNotification()
|
||||||
callback(failedItem)
|
callback(failedItem)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun importFilesFromUris(items: ArrayList<OperationFile>, uris: List<Uri>, callback: (String?) -> Unit){
|
fun importFilesFromUris(items: ArrayList<OperationFile>, uris: List<Uri>, callback: (String?) -> Unit){
|
||||||
Thread {
|
Thread {
|
||||||
|
val notificationBuilder = showNotification(getString(R.string.file_op_import_msg), items.size)
|
||||||
var failedIndex = -1
|
var failedIndex = -1
|
||||||
for (i in 0 until items.size) {
|
for (i in 0 until items.size) {
|
||||||
try {
|
try {
|
||||||
@ -118,12 +168,16 @@ class FileOperationService : Service() {
|
|||||||
} catch (e: FileNotFoundException){
|
} catch (e: FileNotFoundException){
|
||||||
failedIndex = i
|
failedIndex = i
|
||||||
}
|
}
|
||||||
if (failedIndex != -1){
|
if (failedIndex == -1) {
|
||||||
|
updateNotificationProgress(notificationBuilder, i, items.size)
|
||||||
|
} else {
|
||||||
|
cancelNotification()
|
||||||
callback(uris[failedIndex].toString())
|
callback(uris[failedIndex].toString())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedIndex == -1){
|
if (failedIndex == -1){
|
||||||
|
cancelNotification()
|
||||||
callback(null)
|
callback(null)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
@ -131,13 +185,17 @@ class FileOperationService : Service() {
|
|||||||
|
|
||||||
fun wipeUris(uris: List<Uri>, callback: (String?) -> Unit){
|
fun wipeUris(uris: List<Uri>, callback: (String?) -> Unit){
|
||||||
Thread {
|
Thread {
|
||||||
|
val notificationBuilder = showNotification(getString(R.string.file_op_wiping_msg), uris.size)
|
||||||
var errorMsg: String? = null
|
var errorMsg: String? = null
|
||||||
for (uri in uris) {
|
for (i in uris.indices) {
|
||||||
errorMsg = Wiper.wipe(this, uri)
|
errorMsg = Wiper.wipe(this, uris[i])
|
||||||
if (errorMsg != null) {
|
if (errorMsg == null) {
|
||||||
|
updateNotificationProgress(notificationBuilder, i, uris.size)
|
||||||
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cancelNotification()
|
||||||
callback(errorMsg)
|
callback(errorMsg)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
@ -146,10 +204,10 @@ class FileOperationService : Service() {
|
|||||||
val outputStream = treeDocumentFile.createFile("*/*", File(srcPath).name)?.uri?.let {
|
val outputStream = treeDocumentFile.createFile("*/*", File(srcPath).name)?.uri?.let {
|
||||||
contentResolver.openOutputStream(it)
|
contentResolver.openOutputStream(it)
|
||||||
}
|
}
|
||||||
return if (outputStream != null){
|
return if (outputStream == null) {
|
||||||
gocryptfsVolume.exportFile(srcPath, outputStream)
|
|
||||||
} else {
|
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
gocryptfsVolume.exportFile(srcPath, outputStream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,17 +234,21 @@ class FileOperationService : Service() {
|
|||||||
Thread {
|
Thread {
|
||||||
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
DocumentFile.fromTreeUri(this, uri)?.let { treeDocumentFile ->
|
DocumentFile.fromTreeUri(this, uri)?.let { treeDocumentFile ->
|
||||||
|
val notificationBuilder = showNotification(getString(R.string.file_op_export_msg), items.size)
|
||||||
var failedItem: String? = null
|
var failedItem: String? = null
|
||||||
for (element in items) {
|
for (i in items.indices) {
|
||||||
failedItem = if (element.isDirectory) {
|
failedItem = if (items[i].isDirectory) {
|
||||||
recursiveExportDirectory(element.fullPath, treeDocumentFile)
|
recursiveExportDirectory(items[i].fullPath, treeDocumentFile)
|
||||||
} else {
|
} else {
|
||||||
if (exportFileInto(element.fullPath, treeDocumentFile)) null else element.fullPath
|
if (exportFileInto(items[i].fullPath, treeDocumentFile)) null else items[i].fullPath
|
||||||
}
|
}
|
||||||
if (failedItem != null) {
|
if (failedItem == null) {
|
||||||
|
updateNotificationProgress(notificationBuilder, i, items.size)
|
||||||
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cancelNotification()
|
||||||
callback(failedItem)
|
callback(failedItem)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
|
@ -186,4 +186,11 @@
|
|||||||
<string name="hidden_volume_warning">Hidden volumes are stored in the app\'s internal storage. Other apps can\'t see these volumes without root access. However, if you uninstall DroidFS or clear data of the app, all your hidden volumes will be LOST. Be sure to make backups !</string>
|
<string name="hidden_volume_warning">Hidden volumes are stored in the app\'s internal storage. Other apps can\'t see these volumes without root access. However, if you uninstall DroidFS or clear data of the app, all your hidden volumes will be LOST. Be sure to make backups !</string>
|
||||||
<string name="camera_perm_needed">Camera permission is needed to take photo.</string>
|
<string name="camera_perm_needed">Camera permission is needed to take photo.</string>
|
||||||
<string name="choose_resolution">Choose a resolution</string>
|
<string name="choose_resolution">Choose a resolution</string>
|
||||||
|
<string name="file_operations">File Operations</string>
|
||||||
|
<string name="file_op_notification_title">File Operations running…</string>
|
||||||
|
<string name="file_op_copy_msg">Copying files…</string>
|
||||||
|
<string name="file_op_import_msg">Importing files…</string>
|
||||||
|
<string name="file_op_export_msg">Exporting files…</string>
|
||||||
|
<string name="file_op_move_msg">Moving files…</string>
|
||||||
|
<string name="file_op_wiping_msg">Wiping files…</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user