From 2765d78899fed642151b1ae1a8a89a699f7ec8d5 Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Wed, 7 Jan 2026 23:32:52 +0100 Subject: [PATCH] InfiniTime: Fix corrupted fonts and images --- .../btle/ResourceUploadProgressListener.java | 35 ---- .../btle/profiles/adablefs/AdaBleFsProfile.kt | 164 +++++++++++++----- .../btle/profiles/adablefs/AdaFsEntry.kt | 25 --- .../adablefs/RemoteFileSystemCache.kt | 67 ------- .../devices/pinetime/PineTimeJFSupport.java | 141 +++------------ 5 files changed, 137 insertions(+), 295 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ResourceUploadProgressListener.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaFsEntry.kt delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/RemoteFileSystemCache.kt diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ResourceUploadProgressListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ResourceUploadProgressListener.java deleted file mode 100644 index 8e4cf30131..0000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ResourceUploadProgressListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2016-2022 Andreas Shimokawa, Carsten Pfeiffer, JF, Sebastian - Kranz, Taavi Eomäe - - This file is part of Gadgetbridge. - - Gadgetbridge 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. - - Gadgetbridge 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 . */ -package nodomain.freeyourgadget.gadgetbridge.service.btle; - -public class ResourceUploadProgressListener { - public void onDeviceConnecting(final String mac) { } - public void onDeviceConnected(final String mac) { } - public void onUploadStarting(final String mac) { } - public void onDeviceDisconnecting(final String mac) { } - public void onDeviceDisconnected(final String mac) { } - public void onUploadCompleted(final String mac) { } - public void onUploadAborted(final String mac) { } - public void onError(final String mac, int error, int errorType, final String message) { } - public void onProgressChanged(final String mac, - int percent, - float speed, - float averageSpeed, - int segment, - int totalSegments) { } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaBleFsProfile.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaBleFsProfile.kt index 09ad1faddd..d265cae97c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaBleFsProfile.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaBleFsProfile.kt @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothGattCharacteristic import android.content.Context import android.content.Intent import android.net.Uri +import com.google.protobuf.LazyStringArrayList.emptyList import nodomain.freeyourgadget.gadgetbridge.R import nodomain.freeyourgadget.gadgetbridge.devices.pinetime.PineTimeJFConstants import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice @@ -29,7 +30,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEQueue import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile -import nodomain.freeyourgadget.gadgetbridge.util.RemoteFileSystemCache import nodomain.freeyourgadget.gadgetbridge.util.UriHelper import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException import org.json.JSONObject @@ -74,35 +74,79 @@ class AdaBleFsProfile(support: T) : Abstrac private var currentBuilder: TransactionBuilder? = null private var device: GBDevice? = null private val adaBleFsQueue: ArrayDeque = ArrayDeque() - private var offsetToWriteTo = 0 - private var chunkSize = 240 // Maximum possible within MTU - private val remoteFs = RemoteFileSystemCache() + private var currentAction: AdaBleFsAction? = null + private var bytesWritten = 0 + private var bytesProgress = 0 + private var bytesTotal = 0 + private var chunkSize = 235 // Maximum possible within MTU + private var watchFsContents: MutableList = ArrayList() private var listingDirectory: List = emptyList() private var allActionsCount = 0 private var currentActionNr = 0 fun loadResources(uri: Uri, context: Context, queue: BtLEQueue) { btleQueue = queue + watchFsContents = ArrayList() try { + // Retrieve directory listing for finding and deleting existing files + adaBleFsQueue.addFirst( + AdaBleFsAction( + AdaBleFsAction.Method.LIST_DIRECTORY, + "/" + ) + ) + allActionsCount++ val uriHelper = UriHelper.get(uri, context) val zipPackage = GBZipFile(uriHelper.openInputStream()) val resourcesManifest = JSONObject(String(zipPackage.getFileFromZip("resources.json"))) - val resources = resourcesManifest.getJSONArray("resources") - // TODO: add support for deleting files in the obsolete_files array + // Delete files declared obsolete in the manifest + var resources = resourcesManifest.getJSONArray("obsolete_files") for (i in 0 until resources.length()) { val fileItem = resources.getJSONObject(i) val filePath = fileItem.getString("path") - val fileName = fileItem.getString("filename") - LOG.info("Adding to queue: UPLOAD, $fileName, $filePath") + LOG.info("Adding to queue: DELETE (obsolete), $filePath") adaBleFsQueue.add( AdaBleFsAction( - AdaBleFsAction.Method.UPLOAD, - filePath, - zipPackage.getFileFromZip(fileName) + AdaBleFsAction.Method.DELETE, + filePath ) ) allActionsCount += 1 } + // Upload new/updated resource files + resources = resourcesManifest.getJSONArray("resources") + for (i in 0 until resources.length()) { + val fileItem = resources.getJSONObject(i) + val filePath = fileItem.getString("path") + val fileName = fileItem.getString("filename") + LOG.info("Adding to queue: DELETE, $filePath") + adaBleFsQueue.add( + AdaBleFsAction( + AdaBleFsAction.Method.DELETE, + filePath + ) + ) + allActionsCount += 1 + val fileData = zipPackage.getFileFromZip(fileName) + bytesTotal += fileData.size + LOG.info("Adding to queue: UPLOAD, $fileName, $filePath, ${fileData.size} bytes") + adaBleFsQueue.add( + AdaBleFsAction( + AdaBleFsAction.Method.UPLOAD, + filePath, + fileData + ) + ) + allActionsCount += 1 + } + // This directory listing is only useful to get some data in the log + adaBleFsQueue.add( + AdaBleFsAction( + AdaBleFsAction.Method.LIST_DIRECTORY, + "/" + ) + ) + allActionsCount++ } catch (e: ZipFileException) { LOG.error("Unable to read the zip file.", e) } catch (e: FileNotFoundException) { @@ -122,17 +166,19 @@ class AdaBleFsProfile(support: T) : Abstrac @Throws(IOException::class) private fun startNextAdaFsAction() { - val nextAction = adaBleFsQueue.firstOrNull()// ?: return - if (nextAction == null) { - notify(createIntent("", false)) + try { + currentAction = adaBleFsQueue.removeFirst() + } catch (e: NoSuchElementException) { + notify(createIntent(false)) return } currentActionNr++ - when (nextAction.method) { + when (currentAction!!.method) { AdaBleFsAction.Method.UPLOAD -> uploadFileStart() AdaBleFsAction.Method.DELETE -> deleteFile() + AdaBleFsAction.Method.LIST_DIRECTORY -> listDirectoryFromQueue() else -> { - LOG.warn("Skipping unimplemented AdaBleFsAction method ${nextAction.method}") + LOG.warn("Skipping unimplemented AdaBleFsAction method ${currentAction!!.method}") } } } @@ -176,7 +222,6 @@ class AdaBleFsProfile(support: T) : Abstrac else -> LOG.warn("Unknown BLE FS response: ${returned[0]}") } if (actionResult) { - adaBleFsQueue.removeFirst() startNextAdaFsAction() } } @@ -199,7 +244,21 @@ class AdaBleFsProfile(support: T) : Abstrac val fileSize = returned.sliceArray(24..27).foldIndexed(0) { i, acc, b -> acc or ((b.toInt() and 0xFF) shl (8 * i)) } val path = String(returned.copyOfRange(28, 28 + pathLength), Charsets.UTF_8) - remoteFs.updateEntry(path, AdaFsEntry(path, isDirectory, fileSize, timestamp, flags)) + val absPath = "/" + (listingDirectory + path).filter { it.isNotEmpty() }.joinToString("/") + LOG.debug("LISTDIR: $absPath, $fileSize bytes") + if (path.isNotEmpty() && path != "." && path != "..") { + watchFsContents.add(absPath) + if (isDirectory) { + LOG.info("Adding to queue: LISTDIR, $absPath") + adaBleFsQueue.addFirst( + AdaBleFsAction( + AdaBleFsAction.Method.LIST_DIRECTORY, + absPath + ) + ) + allActionsCount++ + } + } return entryNum == totalEntries } @@ -210,28 +269,32 @@ class AdaBleFsProfile(support: T) : Abstrac @Throws(IOException::class) private fun checkContinueFileUpload(returned: ByteArray): Boolean { checkStatus(returned[1]) - offsetToWriteTo = ByteBuffer.wrap(returned, 4, 4).order(ByteOrder.LITTLE_ENDIAN).int + val offset = ByteBuffer.wrap(returned, 4, 4).order(ByteOrder.LITTLE_ENDIAN).int val sizeLeft = ByteBuffer.wrap(returned, 16, 4).order(ByteOrder.LITTLE_ENDIAN).int - LOG.debug("Status from watch: ${returned[1]}, offset=$offsetToWriteTo, sizeLeft=$sizeLeft") - if (sizeLeft > 0) uploadNextFileChunk() - return sizeLeft == 0 + LOG.debug("Status from watch: ${returned[1]}, offset=$offset, sizeLeft=$sizeLeft") + if (bytesWritten < currentAction!!.data.size) { + uploadNextFileChunk() + return false + } + return true } @Throws(IOException::class) private fun uploadFileStart() { - val nextAction = adaBleFsQueue.first() val unixTime = System.currentTimeMillis() / 1000L - val pathBytes = nextAction.filenameorpath.toByteArray() + val pathBytes = currentAction!!.filenameorpath.toByteArray() val buffer = ByteBuffer.allocate(1 + 1 + 2 + 4 + 8 + 4 + pathBytes.size).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_WRITE_FILE_START) buffer.put(PADDING_BYTE) buffer.putShort(pathBytes.size.toShort()) buffer.putInt(0) buffer.putLong(unixTime) - buffer.putInt(nextAction.data.size) + buffer.putInt(currentAction!!.data.size) buffer.put(pathBytes) - LOG.info("Sending start packet for ${nextAction.filenameorpath} (${nextAction.data.size} bytes)") + bytesWritten = 0 + LOG.info("Sending start packet for ${currentAction!!.filenameorpath} (${currentAction!!.data.size} bytes)") + notify(createIntent(true)) currentBuilder = performInitialized("Upload file start") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.queue() @@ -239,46 +302,51 @@ class AdaBleFsProfile(support: T) : Abstrac @Throws(IOException::class) private fun uploadNextFileChunk() { - val nextAction = adaBleFsQueue.first() - val toSendSize = minOf(chunkSize, nextAction.data.size - offsetToWriteTo) + val toSendSize = minOf(chunkSize, currentAction!!.data.size - bytesWritten) val buffer = ByteBuffer.allocate(2 + 2 + 4 + 4 + toSendSize).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_WRITE_FILE_DATA) buffer.put(REQUEST_CONTINUED) buffer.put(PADDING_BYTE) buffer.put(PADDING_BYTE) - buffer.putInt(offsetToWriteTo + toSendSize) // next chunk offset + buffer.putInt(bytesWritten) buffer.putInt(toSendSize) - buffer.put(nextAction.data, offsetToWriteTo, toSendSize) + buffer.put(currentAction!!.data, bytesWritten, toSendSize) - val percentage = (((offsetToWriteTo+toSendSize).toFloat() / nextAction.data.size.toFloat()) * 100).roundToInt() - LOG.info("Sending chunk of $toSendSize bytes ($percentage%) for ${nextAction.filenameorpath}, next chunk starts at offset $offsetToWriteTo") - notify(createIntent(nextAction.filenameorpath, true)) + bytesProgress += toSendSize + val percentage = ((bytesProgress.toFloat() / bytesTotal.toFloat()) * 100).roundToInt() + LOG.info("Sending chunk of $toSendSize bytes for ${currentAction!!.filenameorpath}, at offset $bytesWritten") + notify(createIntent(true)) currentBuilder = performInitialized("Upload file chunk") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.setProgress(R.string.uploading_resources, true, percentage) currentBuilder?.queue() + bytesWritten += toSendSize } @Throws(IOException::class) private fun deleteFile() { - val nextAction = adaBleFsQueue.first() - val pathBytes = nextAction.filenameorpath.toByteArray() + if (!watchFsContents.contains(currentAction!!.filenameorpath)) { + LOG.info("Not deleting non-existent file: ${currentAction!!.filenameorpath}") + startNextAdaFsAction() + return + } + val pathBytes = currentAction!!.filenameorpath.toByteArray() val buffer = ByteBuffer.allocate(2 + 2 + pathBytes.size).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_DELETE_FILE) buffer.put(PADDING_BYTE) buffer.putShort(pathBytes.size.toShort()) buffer.put(pathBytes) - currentBuilder = performInitialized("Delete file or directory") + notify(createIntent(true)) + currentBuilder = performInitialized("Delete file or directory: ${currentAction!!.filenameorpath}") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.queue() } @Throws(IOException::class) private fun makeDirectory() { - val nextAction = adaBleFsQueue.first() val unixTime = System.currentTimeMillis() / 1000L - val pathBytes = nextAction.filenameorpath.toByteArray() + val pathBytes = currentAction!!.filenameorpath.toByteArray() val buffer = ByteBuffer.allocate(2 + 2 + 4 + 8 + pathBytes.size).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_MAKE_DIRECTORY) buffer.put(PADDING_BYTE) @@ -287,6 +355,7 @@ class AdaBleFsProfile(support: T) : Abstrac buffer.putLong(unixTime) buffer.put(pathBytes) + notify(createIntent(true)) currentBuilder = performInitialized("Create directory") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.queue() @@ -294,9 +363,8 @@ class AdaBleFsProfile(support: T) : Abstrac @Throws(IOException::class) private fun moveFileOrDirectory() { - val nextAction = adaBleFsQueue.first() - val firstPathBytes = nextAction.filenameorpath.toByteArray() - val secondPathBytes = nextAction.secondFilenameorpath.toByteArray() + val firstPathBytes = currentAction!!.filenameorpath.toByteArray() + val secondPathBytes = currentAction!!.secondFilenameorpath.toByteArray() val buffer = ByteBuffer.allocate(2 + 4 + firstPathBytes.size + secondPathBytes.size).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_MOVE_FILE_DIRECTORY) buffer.put(PADDING_BYTE) @@ -306,31 +374,33 @@ class AdaBleFsProfile(support: T) : Abstrac buffer.put(PADDING_BYTE) buffer.put(secondPathBytes) + notify(createIntent(true)) currentBuilder = performInitialized("Move file or directory") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.queue() } @Throws(IOException::class) - private fun requestListDirectory(path: String) { - val pathBytes = path.toByteArray() + private fun listDirectoryFromQueue() { + listingDirectory = currentAction!!.filenameorpath.split("/").filter { it.isNotEmpty() } + val pathBytes = currentAction!!.filenameorpath.toByteArray() val buffer = ByteBuffer.allocate(2 + 2 + pathBytes.size).order(ByteOrder.LITTLE_ENDIAN) buffer.put(REQUEST_LIST_DIRECTORY) buffer.put(PADDING_BYTE) buffer.putShort(pathBytes.size.toShort()) buffer.put(pathBytes) + notify(createIntent(true)) currentBuilder = performInitialized("List directory") currentBuilder?.write(UUID_CHARACTERISTIC_FS_TRANSFER, *buffer.array()) currentBuilder?.queue() - - listingDirectory = path.split("/") } - private fun createIntent(filename: String, ongoing: Boolean): Intent { + private fun createIntent(ongoing: Boolean): Intent { val intent = Intent(PineTimeJFConstants.ACTION_UPLOAD_PROGRESS) intent.putExtra("ongoing", ongoing) - intent.putExtra("filename", filename) + intent.putExtra("filename", currentAction!!.filenameorpath) + intent.putExtra("currentAction", currentAction!!.method.toString()) intent.putExtra("currentActionNr", currentActionNr) intent.putExtra("allActionsCount", allActionsCount) return intent diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaFsEntry.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaFsEntry.kt deleted file mode 100644 index a839ddcc61..0000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/AdaFsEntry.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright (C) 2025 Arjan Schrijver - - This file is part of Gadgetbridge. - - Gadgetbridge 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. - - Gadgetbridge 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 . */ -package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.adablefs - -data class AdaFsEntry( - val path: String, - val isDirectory: Boolean, - val fileSize: Int, - val timestamp: Long, - val flags: Int -) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/RemoteFileSystemCache.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/RemoteFileSystemCache.kt deleted file mode 100644 index a648808eb2..0000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/adablefs/RemoteFileSystemCache.kt +++ /dev/null @@ -1,67 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.util - -import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.adablefs.AdaFsEntry - -/** - * Type-safe cache for remote filesystem. - * Directories are maps, files are AdaFsEntry objects. - */ -class RemoteFileSystemCache { - - private val root = mutableMapOf() - - fun updateEntry(path: String, entry: AdaFsEntry) { - val parts = path.trim('/').split("/") - var current: MutableMap = root - for ((index, part) in parts.withIndex()) { - if (index == parts.lastIndex) { - current[part] = entry - } else { - current = (current[part] as? MutableMap) ?: mutableMapOf().also { - current[part] = it - } - } - } - } - - fun directoryExists(path: String): Boolean { - val parts = path.trim('/').split("/") - var current: Map = root - for (part in parts) { - val next = current[part] ?: return false - current = next as? Map ?: return false - } - return true - } - - fun getEntry(path: String): AdaFsEntry? { - val parts = path.trim('/').split("/") - var current: Any = root - for (part in parts) { - current = (current as? Map<*, *>)?.get(part) ?: return null - } - return current as? AdaFsEntry - } - - fun removeEntry(path: String) { - val parts = path.trim('/').split("/") - var current: MutableMap = root - for ((index, part) in parts.withIndex()) { - if (index == parts.lastIndex) { - current.remove(part) - } else { - current = (current[part] as? MutableMap) ?: return - } - } - } - - fun listDirectory(path: String): List { - val parts = path.trim('/').split("/") - var current: Any = root - for (part in parts) { - current = (current as? Map)?.get(part) ?: return emptyList() - } - val dir = current as? Map ?: return emptyList() - return dir.values.mapNotNull { it as? AdaFsEntry } - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java index 5b1c789245..420b93b3de 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pinetime/PineTimeJFSupport.java @@ -95,7 +95,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLESingleDevic import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService; -import nodomain.freeyourgadget.gadgetbridge.service.btle.ResourceUploadProgressListener; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.adablefs.AdaBleFsProfile; @@ -114,7 +113,6 @@ public class PineTimeJFSupport extends AbstractBTLESingleDeviceSupport implement private final DeviceInfoProfile deviceInfoProfile; private final BatteryInfoProfile batteryInfoProfile; - private final AdaBleFsProfile adaBleFsProfile; private final int MaxNotificationLength = 100; @@ -255,102 +253,6 @@ public class PineTimeJFSupport extends AbstractBTLESingleDeviceSupport implement } }; - private final ResourceUploadProgressListener resourceUploadProgressListener = new ResourceUploadProgressListener() { - private final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getContext()); - - /** - * Sets the progress bar to indeterminate or not, also makes it visible - * - * @param indeterminate if indeterminate - */ - public void setIndeterminate(boolean indeterminate) { - manager.sendBroadcast(new Intent(GB.ACTION_SET_PROGRESS_BAR).putExtra(GB.PROGRESS_BAR_INDETERMINATE, indeterminate)); - } - - /** - * Sets the status text and logs it - */ - public void setProgress(int progress) { - manager.sendBroadcast(new Intent(GB.ACTION_SET_PROGRESS_BAR).putExtra(GB.PROGRESS_BAR_PROGRESS, progress)); - } - - /** - * Sets the text that describes progress - * - * @param progressText text to display - */ - public void setProgressText(String progressText) { - manager.sendBroadcast(new Intent(GB.ACTION_SET_PROGRESS_TEXT).putExtra(GB.DISPLAY_MESSAGE_MESSAGE, progressText)); - } - - @Override - public void onDeviceConnecting(final String mac) { - this.setIndeterminate(true); - this.setProgressText(getContext().getString(R.string.devicestatus_connecting)); - } - - @Override - public void onDeviceConnected(final String mac) { - this.setIndeterminate(true); - this.setProgressText(getContext().getString(R.string.devicestatus_connected)); - } - - @Override - public void onUploadStarting(final String mac) { - this.setIndeterminate(true); - this.setProgressText(getContext().getString(R.string.devicestatus_upload_starting)); - } - - @Override - public void onDeviceDisconnecting(final String mac) { - this.setProgressText(getContext().getString(R.string.devicestatus_disconnecting)); - } - - @Override - public void onDeviceDisconnected(final String mac) { - this.setIndeterminate(true); - this.setProgressText(getContext().getString(R.string.devicestatus_disconnected)); - } - - @Override - public void onUploadCompleted(final String mac) { - this.setProgressText(getContext().getString(R.string.devicestatus_upload_completed)); - this.setIndeterminate(false); - this.setProgress(100); - - handler = null; - controller = null; - gbDevice.unsetBusyTask(); - // TODO: Request reconnection - } - - @Override - public void onUploadAborted(final String mac) { - this.setProgressText(getContext().getString(R.string.devicestatus_upload_aborted)); - gbDevice.unsetBusyTask(); - } - - @Override - public void onError(final String mac, int error, int errorType, final String message) { - this.setProgressText(getContext().getString(R.string.devicestatus_upload_failed)); - gbDevice.unsetBusyTask(); - } - - @Override - public void onProgressChanged(final String mac, - int percent, - float speed, - float averageSpeed, - int segment, - int totalSegments) { - this.setProgress(percent); - this.setIndeterminate(false); - this.setProgressText(String.format(Locale.ENGLISH, - getContext().getString(R.string.firmware_update_progress), - percent, speed, averageSpeed, segment, totalSegments)); - } - }; - public PineTimeJFSupport() { super(LOG); addSupportedService(GattService.UUID_SERVICE_ALERT_NOTIFICATION); @@ -366,30 +268,27 @@ public class PineTimeJFSupport extends AbstractBTLESingleDeviceSupport implement addSupportedService(PineTimeJFConstants.UUID_SERVICE_HEART_RATE); addSupportedService(AdaBleFsProfile.UUID_SERVICE_FS); - IntentListener mListener = new IntentListener() { - @Override - public void notify(Intent intent) { - String action = intent.getAction(); - LOG.info("IntentListener received an intent with ACTION={}", action); - if (DeviceInfoProfile.ACTION_DEVICE_INFO.equals(action)) { - handleDeviceInfo(intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO)); - } else if (BatteryInfoProfile.ACTION_BATTERY_INFO.equals(action)) { - handleBatteryInfo(intent.getParcelableExtra(BatteryInfoProfile.EXTRA_BATTERY_INFO)); - } else if (PineTimeJFConstants.ACTION_UPLOAD_PROGRESS.equals(action)) { - LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getContext()); - boolean ongoing = intent.getBooleanExtra("ongoing", true); - String progressText = ""; - if (ongoing) { - String filename = intent.getStringExtra("filename"); - int currentActionNr = intent.getIntExtra("currentActionNr", 0); - int allActionsCount = intent.getIntExtra("allActionsCount", 0); - progressText = String.format("Performing action %d of %d\nCurrent filename: %s", currentActionNr, allActionsCount, filename); - } else { - progressText = getContext().getString(R.string.devicestatus_upload_completed); - gbDevice.unsetBusyTask(); - } - manager.sendBroadcast(new Intent(GB.ACTION_SET_PROGRESS_TEXT).putExtra(GB.DISPLAY_MESSAGE_MESSAGE, progressText)); + IntentListener mListener = intent -> { + String action = intent.getAction(); + if (DeviceInfoProfile.ACTION_DEVICE_INFO.equals(action)) { + handleDeviceInfo(intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO)); + } else if (BatteryInfoProfile.ACTION_BATTERY_INFO.equals(action)) { + handleBatteryInfo(intent.getParcelableExtra(BatteryInfoProfile.EXTRA_BATTERY_INFO)); + } else if (PineTimeJFConstants.ACTION_UPLOAD_PROGRESS.equals(action)) { + LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getContext()); + boolean ongoing = intent.getBooleanExtra("ongoing", true); + String progressText = ""; + if (ongoing) { + String filename = intent.getStringExtra("filename"); + String currentAction = intent.getStringExtra("currentAction"); + int currentActionNr = intent.getIntExtra("currentActionNr", 0); + int allActionsCount = intent.getIntExtra("allActionsCount", 0); + progressText = String.format("Performing action %d of %d\n%s %s", currentActionNr, allActionsCount, currentAction, filename); + } else { + progressText = getContext().getString(R.string.devicestatus_upload_completed); + gbDevice.unsetBusyTask(); } + manager.sendBroadcast(new Intent(GB.ACTION_SET_PROGRESS_TEXT).putExtra(GB.DISPLAY_MESSAGE_MESSAGE, progressText)); } };