Implement writing macOS DMG images
This commit is contained in:
parent
e35d244124
commit
d49d3d7325
7 changed files with 275 additions and 97 deletions
|
@ -10,7 +10,8 @@ import eu.depau.etchdroid.StateKeeper
|
||||||
import eu.depau.etchdroid.enums.FlashMethod
|
import eu.depau.etchdroid.enums.FlashMethod
|
||||||
import eu.depau.etchdroid.enums.WizardStep
|
import eu.depau.etchdroid.enums.WizardStep
|
||||||
import eu.depau.etchdroid.kotlin_exts.*
|
import eu.depau.etchdroid.kotlin_exts.*
|
||||||
import eu.depau.etchdroid.services.UsbAPIWriteService
|
import eu.depau.etchdroid.services.UsbApiDmgWriteService
|
||||||
|
import eu.depau.etchdroid.services.UsbApiImgWriteService
|
||||||
import kotlinx.android.synthetic.main.fragment_confirminfo.view.*
|
import kotlinx.android.synthetic.main.fragment_confirminfo.view.*
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
|
@ -29,7 +30,12 @@ class ConfirmInfoFragment : WizardFragment() {
|
||||||
|
|
||||||
context?.toast("Check notification for progress")
|
context?.toast("Check notification for progress")
|
||||||
|
|
||||||
val intent = Intent(activity, UsbAPIWriteService::class.java)
|
val intent: Intent = when (StateKeeper.flashMethod) {
|
||||||
|
FlashMethod.FLASH_API -> Intent(activity, UsbApiImgWriteService::class.java)
|
||||||
|
FlashMethod.FLASH_DMG_API -> Intent(activity, UsbApiDmgWriteService::class.java)
|
||||||
|
else -> null!!
|
||||||
|
}
|
||||||
|
|
||||||
intent.setDataAndType(StateKeeper.imageFile, "application/octet-stream")
|
intent.setDataAndType(StateKeeper.imageFile, "application/octet-stream")
|
||||||
intent.putExtra("usbDevice", StateKeeper.usbDevice)
|
intent.putExtra("usbDevice", StateKeeper.usbDevice)
|
||||||
activity?.startService(intent)
|
activity?.startService(intent)
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
package eu.depau.etchdroid.services
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.hardware.usb.UsbDevice
|
|
||||||
import android.net.Uri
|
|
||||||
import android.util.Log
|
|
||||||
import com.github.mjdev.libaums.UsbMassStorageDevice
|
|
||||||
import eu.depau.etchdroid.kotlin_exts.getFileName
|
|
||||||
import eu.depau.etchdroid.kotlin_exts.getFileSize
|
|
||||||
import eu.depau.etchdroid.kotlin_exts.name
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
class UsbAPIWriteService : UsbWriteService("UsbAPIWriteService") {
|
|
||||||
// 512 * 32 bytes = USB max transfer size
|
|
||||||
val DD_BLOCKSIZE = 512 * 32 * 64 // 1 MB
|
|
||||||
|
|
||||||
class Action {
|
|
||||||
val WRITE_IMAGE = "eu.depau.etchdroid.action.API_WRITE_IMAGE"
|
|
||||||
val WRITE_CANCEL = "eu.depau.etchdroid.action.API_WRITE_CANCEL"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getUsbMSDevice(usbDevice: UsbDevice): UsbMassStorageDevice? {
|
|
||||||
val msDevs = UsbMassStorageDevice.getMassStorageDevices(this)
|
|
||||||
|
|
||||||
for (dev in msDevs) {
|
|
||||||
if (dev.usbDevice == usbDevice)
|
|
||||||
return dev
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun writeImage(intent: Intent): Long {
|
|
||||||
val uri: Uri = intent.data!!
|
|
||||||
val usbDevice: UsbDevice = intent.getParcelableExtra("usbDevice")
|
|
||||||
|
|
||||||
val msDev = getUsbMSDevice(usbDevice)!!
|
|
||||||
msDev.init()
|
|
||||||
|
|
||||||
val blockDev = msDev.blockDevice
|
|
||||||
val bsFactor = DD_BLOCKSIZE / blockDev.blockSize
|
|
||||||
val byteBuffer = ByteBuffer.allocate(blockDev.blockSize * bsFactor)
|
|
||||||
val imageSize = uri.getFileSize(this)
|
|
||||||
val inputStream = contentResolver.openInputStream(uri)!!
|
|
||||||
|
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
|
|
||||||
var readBytes: Int
|
|
||||||
var offset = 0L
|
|
||||||
var writtenBytes: Long = 0
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
wakeLock(true)
|
|
||||||
readBytes = inputStream.read(byteBuffer.array()!!)
|
|
||||||
if (readBytes < 0)
|
|
||||||
break
|
|
||||||
byteBuffer.position(0)
|
|
||||||
|
|
||||||
blockDev.write(offset, byteBuffer)
|
|
||||||
offset += bsFactor
|
|
||||||
writtenBytes += readBytes
|
|
||||||
|
|
||||||
updateNotification(usbDevice.name, uri.getFileName(this), offset * blockDev.blockSize, imageSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
resultNotification(usbDevice.name, uri.getFileName(this)!!, true, writtenBytes, startTime)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
resultNotification(usbDevice.name, uri.getFileName(this)!!, false, writtenBytes, startTime)
|
|
||||||
Log.e(TAG, "Could't write image to ${usbDevice.name}")
|
|
||||||
throw e
|
|
||||||
} finally {
|
|
||||||
wakeLock(false)
|
|
||||||
msDev.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG, "Written $writtenBytes bytes to ${usbDevice.name} using API")
|
|
||||||
return writtenBytes
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
package eu.depau.etchdroid.services
|
||||||
|
|
||||||
|
import android.hardware.usb.UsbDevice
|
||||||
|
import android.net.Uri
|
||||||
|
import com.google.common.util.concurrent.SimpleTimeLimiter
|
||||||
|
import com.google.common.util.concurrent.TimeLimiter
|
||||||
|
import com.google.common.util.concurrent.UncheckedTimeoutException
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getBinary
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getFileName
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getFileSize
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.name
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.TimeoutException
|
||||||
|
|
||||||
|
val plistRegex = Regex("\\s*partition (\\d+): begin=(\\d+), size=(\\d+), decoded=(\\d+), firstsector=(\\d+), sectorcount=(\\d+), blocksruncount=(\\d+)\\s*")
|
||||||
|
//val progressRegex = Regex("\\[?(\\d+)]\\s+(\\d+[.,]\\d+)%")
|
||||||
|
|
||||||
|
class UsbApiDmgWriteService : UsbApiWriteService("UsbApiDmgWriteService") {
|
||||||
|
val SECTOR_SIZE = 512
|
||||||
|
|
||||||
|
private lateinit var uri: Uri
|
||||||
|
private lateinit var process: Process
|
||||||
|
private lateinit var errReader: BufferedReader
|
||||||
|
|
||||||
|
private var bytesTotal = 0
|
||||||
|
|
||||||
|
private var readTimeLimiter: TimeLimiter = SimpleTimeLimiter.create(Executors.newCachedThreadPool())
|
||||||
|
|
||||||
|
override fun getSendProgress(usbDevice: UsbDevice, uri: Uri): (Long) -> Unit {
|
||||||
|
val imageSize = uri.getFileSize(this)
|
||||||
|
return { bytes ->
|
||||||
|
// asyncReadProcessProgress()
|
||||||
|
|
||||||
|
try {
|
||||||
|
readTimeLimiter.callWithTimeout({
|
||||||
|
val byteArray = ByteArray(128)
|
||||||
|
process.errorStream.read(byteArray)
|
||||||
|
System.err.write(byteArray)
|
||||||
|
}, 100, TimeUnit.MILLISECONDS)
|
||||||
|
} catch (e: TimeoutException) {
|
||||||
|
} catch (e: UncheckedTimeoutException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
val perc = if (bytesTotal == 0)
|
||||||
|
-1
|
||||||
|
else
|
||||||
|
(bytes.toDouble() / bytesTotal.toDouble() * 100).toInt()
|
||||||
|
|
||||||
|
updateNotification(usbDevice.name, uri.getFileName(this), bytes, perc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// fun asyncReadProcessProgress() {
|
||||||
|
// val startTime = System.currentTimeMillis()
|
||||||
|
// var c: Int
|
||||||
|
// val charArray = CharArray(20)
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// while (System.currentTimeMillis() < startTime + 50) {
|
||||||
|
// // Skip everything until the first backspace
|
||||||
|
// do
|
||||||
|
// c = readTimeLimiter.callWithTimeout(errReader::read, 50, TimeUnit.MILLISECONDS)
|
||||||
|
// while (c.toChar() != '\b' && c != -1)
|
||||||
|
// // Skip all backspaces
|
||||||
|
// do
|
||||||
|
// c = readTimeLimiter.callWithTimeout(errReader::read, 50, TimeUnit.MILLISECONDS)
|
||||||
|
// while (c.toChar() == '\b' && c != -1)
|
||||||
|
//
|
||||||
|
// // Read the stream
|
||||||
|
// readTimeLimiter.callWithTimeout({errReader.read(charArray)}, 50, TimeUnit.MILLISECONDS)
|
||||||
|
// val match = progressRegex.find(String(charArray)) ?: continue
|
||||||
|
// val (blocksruncurStr, percStr) = match.destructured
|
||||||
|
// val blocksruncur = blocksruncurStr.toInt()
|
||||||
|
//
|
||||||
|
// blocksrun += blocksruncur
|
||||||
|
//
|
||||||
|
// if (blocksruncur >= blocksrunLast)
|
||||||
|
// blocksrun -= blocksrunLast
|
||||||
|
//
|
||||||
|
// blocksrunLast = blocksruncur
|
||||||
|
// }
|
||||||
|
// } catch (e: TimeoutException) {
|
||||||
|
// } catch (e: UncheckedTimeoutException) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun getInputStream(uri: Uri): InputStream {
|
||||||
|
this.uri = uri
|
||||||
|
val pb = ProcessBuilder(getBinary("dmg2img").path, "-v", uri.path, "-")
|
||||||
|
pb.environment()["LD_LIBRARY_PATH"] = applicationInfo.nativeLibraryDir
|
||||||
|
process = pb.start()
|
||||||
|
errReader = process.errorStream.bufferedReader()
|
||||||
|
|
||||||
|
// Read blocksruncount
|
||||||
|
var matched = false
|
||||||
|
var lastSector = 0
|
||||||
|
while (true) {
|
||||||
|
val line = errReader.readLine() ?: break
|
||||||
|
val match = plistRegex.find(line) ?: if (matched) break else continue
|
||||||
|
matched = true
|
||||||
|
|
||||||
|
val (begin, size, decoded, firstsector, sectorcount, blocksruncount) = match.destructured
|
||||||
|
|
||||||
|
val partLastSector = firstsector.toInt() + sectorcount.toInt()
|
||||||
|
if (partLastSector > lastSector)
|
||||||
|
lastSector = partLastSector
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesTotal = lastSector * SECTOR_SIZE
|
||||||
|
return process.inputStream
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package eu.depau.etchdroid.services
|
||||||
|
|
||||||
|
import android.hardware.usb.UsbDevice
|
||||||
|
import android.net.Uri
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getFileName
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getFileSize
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.name
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class UsbApiImgWriteService : UsbApiWriteService("UsbApiImgWriteService") {
|
||||||
|
override fun getSendProgress(usbDevice: UsbDevice, uri: Uri): (Long) -> Unit {
|
||||||
|
val imageSize = uri.getFileSize(this)
|
||||||
|
return { bytes ->
|
||||||
|
updateNotification(usbDevice.name, uri.getFileName(this), bytes, (bytes.toFloat() / imageSize * 100).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInputStream(uri: Uri): InputStream {
|
||||||
|
return contentResolver.openInputStream(uri)!!
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package eu.depau.etchdroid.services
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.hardware.usb.UsbDevice
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import com.github.mjdev.libaums.UsbMassStorageDevice
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.getFileName
|
||||||
|
import eu.depau.etchdroid.kotlin_exts.name
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
abstract class UsbApiWriteService(name: String) : UsbWriteService(name) {
|
||||||
|
// 512 * 32 bytes = USB max transfer size
|
||||||
|
val DD_BLOCKSIZE = 512 * 32 * 64 // 1 MB
|
||||||
|
|
||||||
|
class Action {
|
||||||
|
val WRITE_IMAGE = "eu.depau.etchdroid.action.API_WRITE_IMAGE"
|
||||||
|
val WRITE_CANCEL = "eu.depau.etchdroid.action.API_WRITE_CANCEL"
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun getSendProgress(usbDevice: UsbDevice, uri: Uri): (Long) -> Unit
|
||||||
|
abstract fun getInputStream(uri: Uri): InputStream
|
||||||
|
|
||||||
|
private fun getUsbMSDevice(usbDevice: UsbDevice): UsbMassStorageDevice? {
|
||||||
|
val msDevs = UsbMassStorageDevice.getMassStorageDevices(this)
|
||||||
|
|
||||||
|
for (dev in msDevs) {
|
||||||
|
if (dev.usbDevice == usbDevice)
|
||||||
|
return dev
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeInputStream(inputStream: InputStream, msDev: UsbMassStorageDevice, sendProgress: (Long) -> Unit): Long {
|
||||||
|
val blockDev = msDev.blockDevice
|
||||||
|
val bsFactor = DD_BLOCKSIZE / blockDev.blockSize
|
||||||
|
val buffIS = BufferedInputStream(inputStream)
|
||||||
|
val byteBuffer = ByteBuffer.allocate(blockDev.blockSize * bsFactor)
|
||||||
|
|
||||||
|
var lastReadBytes: Int
|
||||||
|
var readBytes = 0
|
||||||
|
var readBlocksBytes = 0
|
||||||
|
var offset = 0L
|
||||||
|
var writtenBytes: Long = 0
|
||||||
|
var remaining = 0
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
wakeLock(true)
|
||||||
|
lastReadBytes = buffIS.read(byteBuffer.array()!!, remaining, byteBuffer.array().size - remaining)
|
||||||
|
if (lastReadBytes < 0 && readBytes > 0) {
|
||||||
|
// EOF, pad with some extra bits until next block
|
||||||
|
if (readBytes % blockDev.blockSize > 0)
|
||||||
|
readBytes += blockDev.blockSize - (readBytes % blockDev.blockSize)
|
||||||
|
} else if (lastReadBytes < 0) {
|
||||||
|
// EOF, we've already written everything
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
readBytes += lastReadBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
byteBuffer.position(0)
|
||||||
|
|
||||||
|
// Ensure written content size is a multiple of the block size
|
||||||
|
remaining = readBytes % blockDev.blockSize
|
||||||
|
readBlocksBytes = readBytes - remaining
|
||||||
|
byteBuffer.limit(readBlocksBytes)
|
||||||
|
|
||||||
|
// Write the buffer to the device
|
||||||
|
blockDev.write(offset, byteBuffer)
|
||||||
|
offset += (readBlocksBytes) / blockDev.blockSize
|
||||||
|
writtenBytes += readBlocksBytes
|
||||||
|
|
||||||
|
// Copy remaining bytes to the beginning of the buffer
|
||||||
|
for (i in 0 until remaining)
|
||||||
|
byteBuffer.array()[i] = byteBuffer.array()[readBlocksBytes + i]
|
||||||
|
|
||||||
|
readBytes = remaining
|
||||||
|
|
||||||
|
sendProgress(writtenBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return writtenBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeImage(intent: Intent): Long {
|
||||||
|
val uri: Uri = intent.data!!
|
||||||
|
val inputStream = getInputStream(uri)
|
||||||
|
|
||||||
|
val usbDevice: UsbDevice = intent.getParcelableExtra("usbDevice")
|
||||||
|
val msDev = getUsbMSDevice(usbDevice)!!
|
||||||
|
msDev.init()
|
||||||
|
|
||||||
|
val sendProgress = getSendProgress(usbDevice, uri)
|
||||||
|
val startTime = System.currentTimeMillis()
|
||||||
|
var writtenBytes: Long = 0
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
writtenBytes = writeInputStream(inputStream, msDev, sendProgress)
|
||||||
|
|
||||||
|
resultNotification(usbDevice.name, uri.getFileName(this)!!, true, writtenBytes, startTime)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
resultNotification(usbDevice.name, uri.getFileName(this)!!, false, writtenBytes, startTime)
|
||||||
|
Log.e(TAG, "Could't write image to ${usbDevice.name}")
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
wakeLock(false)
|
||||||
|
msDev.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Written $writtenBytes bytes to ${usbDevice.name} using API")
|
||||||
|
return writtenBytes
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import android.support.v4.app.NotificationCompat
|
||||||
import eu.depau.etchdroid.R
|
import eu.depau.etchdroid.R
|
||||||
import eu.depau.etchdroid.kotlin_exts.toHRSize
|
import eu.depau.etchdroid.kotlin_exts.toHRSize
|
||||||
import eu.depau.etchdroid.kotlin_exts.toHRTime
|
import eu.depau.etchdroid.kotlin_exts.toHRTime
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
|
||||||
abstract class UsbWriteService(name: String) : IntentService(name) {
|
abstract class UsbWriteService(name: String) : IntentService(name) {
|
||||||
|
@ -30,7 +31,7 @@ abstract class UsbWriteService(name: String) : IntentService(name) {
|
||||||
private val WL_TIMEOUT = 10 * 60 * 1000L
|
private val WL_TIMEOUT = 10 * 60 * 1000L
|
||||||
|
|
||||||
override fun onHandleIntent(intent: Intent?) {
|
override fun onHandleIntent(intent: Intent?) {
|
||||||
startForeground(FOREGROUND_ID, buildForegroundNotification(null, null, -1, -1))
|
startForeground(FOREGROUND_ID, buildForegroundNotification(null, null, -1))
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writeImage(intent!!)
|
writeImage(intent!!)
|
||||||
|
@ -73,20 +74,18 @@ abstract class UsbWriteService(name: String) : IntentService(name) {
|
||||||
NotificationCompat.Builder(this)
|
NotificationCompat.Builder(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateNotification(usbDevice: String, filename: String?, bytes: Long, total: Long) {
|
fun updateNotification(usbDevice: String, filename: String?, bytes: Long, progr: Int) {
|
||||||
// Notification rate limiting
|
// Notification rate limiting
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
if (time <= prevTime + 1000)
|
if (time <= prevTime + 1000)
|
||||||
return
|
return
|
||||||
|
|
||||||
val speed = ((bytes - prevBytes).toDouble() / (time - prevTime).toDouble() * 1000).toHRSize()
|
val speed = max((bytes - prevBytes).toDouble() / (time - prevTime).toDouble() * 1000, 0.0).toHRSize()
|
||||||
prevTime = time
|
prevTime = time
|
||||||
prevBytes = bytes
|
prevBytes = bytes
|
||||||
|
|
||||||
val perc: Int = (bytes.toDouble() / total * 100.0).toInt()
|
|
||||||
|
|
||||||
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
notificationManager.notify(FOREGROUND_ID, buildForegroundNotification(usbDevice, filename, bytes, total, "$perc% • $speed/s"))
|
notificationManager.notify(FOREGROUND_ID, buildForegroundNotification(usbDevice, filename, progr, "$progr% • $speed/s"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resultNotification(usbDevice: String, filename: String, success: Boolean, bytes: Long = 0, startTime: Long = 0) {
|
fun resultNotification(usbDevice: String, filename: String, success: Boolean, bytes: Long = 0, startTime: Long = 0) {
|
||||||
|
@ -102,7 +101,7 @@ abstract class UsbWriteService(name: String) : IntentService(name) {
|
||||||
.setContentText("$usbDevice may have been unplugged while writing.")
|
.setContentText("$usbDevice may have been unplugged while writing.")
|
||||||
.setSubText(dt.toHRTime())
|
.setSubText(dt.toHRTime())
|
||||||
else {
|
else {
|
||||||
val speed = (bytes.toDouble() / dt.toDouble() * 1000).toHRSize() + "/s"
|
val speed = max(bytes.toDouble() / dt.toDouble() * 1000, 0.0).toHRSize() + "/s"
|
||||||
b.setContentTitle("Write finished")
|
b.setContentTitle("Write finished")
|
||||||
.setContentText("$filename successfully written to $usbDevice")
|
.setContentText("$filename successfully written to $usbDevice")
|
||||||
.setSubText("${dt.toHRTime()} • ${bytes.toHRSize()} • $speed")
|
.setSubText("${dt.toHRTime()} • ${bytes.toHRSize()} • $speed")
|
||||||
|
@ -114,23 +113,23 @@ abstract class UsbWriteService(name: String) : IntentService(name) {
|
||||||
notificationManager.notify(RESULT_NOTIFICATION_ID, b.build())
|
notificationManager.notify(RESULT_NOTIFICATION_ID, b.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildForegroundNotification(usbDevice: String?, filename: String?, bytes: Long, total: Long, subText: String? = null): Notification {
|
fun buildForegroundNotification(usbDevice: String?, filename: String?, progr: Int, subText: String? = null, title: String = getString(R.string.notif_writing_img)): Notification {
|
||||||
val progr: Int
|
|
||||||
val indet: Boolean
|
val indet: Boolean
|
||||||
|
val prog: Int
|
||||||
|
|
||||||
if (total < 0) {
|
if (progr < 0) {
|
||||||
progr = 0
|
prog = 0
|
||||||
indet = true
|
indet = true
|
||||||
} else {
|
} else {
|
||||||
progr = (bytes.toFloat() / total * 100).toInt()
|
prog = progr
|
||||||
indet = false
|
indet = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val b = getNotificationBuilder()
|
val b = getNotificationBuilder()
|
||||||
|
|
||||||
b.setContentTitle(getString(R.string.notif_writing_img))
|
b.setContentTitle(title)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setProgress(100, progr, indet)
|
.setProgress(100, prog, indet)
|
||||||
|
|
||||||
if (usbDevice != null && filename != null)
|
if (usbDevice != null && filename != null)
|
||||||
b.setContentText("${filename} to $usbDevice")
|
b.setContentText("${filename} to $usbDevice")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1d7529285a7bdeb4f1eb158d9305494d682e323d
|
Subproject commit fd3763bb07aa06c9b56b3f6d632d475d59f41433
|
Loading…
Reference in a new issue