From 4f3c521f9108d343c27d3172ce83e96db2c5a7bd Mon Sep 17 00:00:00 2001 From: Arjan Schrijver Date: Thu, 27 Nov 2025 23:06:44 +0100 Subject: [PATCH] Fix Bangle.js http requests through internet helper --- .../appmanager/RebbleAppStoreActivity.kt | 2 +- .../banglejs/BangleJSDeviceSupport.java | 50 +++++++++++++++++-- .../gadgetbridge/util/InternetUtils.kt | 30 +++++++++-- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/RebbleAppStoreActivity.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/RebbleAppStoreActivity.kt index 9ce41c4354..0a26507930 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/RebbleAppStoreActivity.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/RebbleAppStoreActivity.kt @@ -93,7 +93,7 @@ class RebbleAppStoreActivity : AbstractGBActivity() { private fun downloadInstallWatchappById(storeId: String) { val appUrl = "https://appstore-api.rebble.io/api/v1/apps/id/$storeId" - val response: JSONObject? = InternetUtils.doRequest(appUrl.toUri()) + val response: JSONObject? = InternetUtils.doJsonRequest(appUrl.toUri()) if (response != null) { val dataArray = response.getJSONArray("data") val firstAppObject = dataArray.getJSONObject(0) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java index 5c7590a9ea..46d3cc9e67 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java @@ -62,6 +62,9 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -882,7 +885,8 @@ public class BangleJSDeviceSupport extends AbstractBTLESingleDeviceSupport { String url = json.getString("url"); final boolean insecure = json.optBoolean("insecure", false); - String method = json.getString("method").toUpperCase(Locale.US); + String method = "GET"; + if (json.has("method")) json.getString("method").toUpperCase(Locale.US); String body = null; if (json.has("body")) @@ -904,9 +908,47 @@ public class BangleJSDeviceSupport extends AbstractBTLESingleDeviceSupport { } if (headers == null) headers = emptyMap(); - JSONObject o = InternetUtils.Companion.doRequest(Uri.parse(url), method, headers, body, "application/json", insecure); - uartTxJSON("http", o); - } + String response = InternetUtils.Companion.doStringRequest(Uri.parse(url), method, headers, body, "application/json", insecure); + JSONObject o = new JSONObject(); + String _xmlPath = ""; + String _xmlReturn = ""; + try { + _xmlPath = json.getString("xpath"); + _xmlReturn = json.getString("return"); + } catch (JSONException ignored) { + } + final String xmlPath = _xmlPath; + final String xmlReturn = _xmlReturn; + if (!xmlPath.isEmpty()) { + try { + Document doc = Jsoup.parse(response); + Elements result = doc.selectXpath(xmlPath); + if (xmlReturn.equals("array")) { + response = null; // don't add it below + JSONArray arr = new JSONArray(); + for (int i = 0; i < result.size(); i++) + arr.put(result.get(i).text()); + o.put("resp", arr); + } else { // else return only first! + response = ""; + if (!result.isEmpty()) + response = result.get(0).text(); + } + } catch (Exception error) { + uartTxJSONError("http", error.toString(), id); + return; + } + } + try { + o.put("t", "http"); + if( id!=null) + o.put("id", id); + if (response!=null) + o.put("resp", response); + } catch (JSONException e) { + GB.toast(getContext(), "HTTP: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR, e); + } + uartTxJSON("http", o); } /** * Handle "force_calendar_sync" packet diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/InternetUtils.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/InternetUtils.kt index 132d634217..45b76d51b6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/InternetUtils.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/InternetUtils.kt @@ -46,14 +46,14 @@ class InternetUtils { /** * Performs an HTTP request to the given URI, optionally allowing insecure connections. */ - fun doRequest( + fun doStringRequest( uri: Uri, method: String = "GET", requestHeaders: Map = emptyMap(), body: String? = null, bodyContentType: String = "text/plain", insecure: Boolean = false - ): JSONObject? { + ): String? { val response: WebResourceResponse? = if (GBApplication.hasDirectInternetAccess()) { directRequest(uri, method, requestHeaders, body, bodyContentType, insecure) } else { @@ -62,8 +62,30 @@ class InternetUtils { if (response == null) return null // Convert response InputStream to String - val text = response.data.bufferedReader().use { it.readText() } - return JSONObject(text) + return response.data.bufferedReader().use { it.readText() } + } + + fun doJsonRequest( + uri: Uri, + method: String = "GET", + requestHeaders: Map = emptyMap(), + body: String? = null, + bodyContentType: String = "text/plain", + insecure: Boolean = false + ): JSONObject? { + val text = doStringRequest( + uri, + method, + requestHeaders, + body, + bodyContentType, + insecure + ) + try { + return JSONObject(text) + } catch (e: Exception) { + return null + } } fun downloadBinaryFile(