From c9cfaa9bd831efd094f2631d52ef560100519d24 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Tue, 3 Jan 2017 15:04:51 +0100 Subject: [PATCH] Pebble: webview. Implement two way communication with JS. The support within JS is a bit hacky and sometimes conflicts with the configuration page. --- .../app_config/js/gadgetbridge_boilerplate.js | 8 ++- .../devices/pebble/PebbleIoThread.java | 6 ++ .../gadgetbridge/util/WebViewSingleton.java | 59 ++++++++++++++++++- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/app/src/main/assets/app_config/js/gadgetbridge_boilerplate.js b/app/src/main/assets/app_config/js/gadgetbridge_boilerplate.js index 3495b0c58..008ae7320 100644 --- a/app/src/main/assets/app_config/js/gadgetbridge_boilerplate.js +++ b/app/src/main/assets/app_config/js/gadgetbridge_boilerplate.js @@ -141,7 +141,11 @@ function gbPebble() { this.sendAppMessage = function (dict, callbackAck, callbackNack){ try { self.configurationValues = JSON.stringify(dict); - document.getElementById("jsondata").innerHTML=self.configurationValues; + if (document.getElementById("step2").style.display == 'block') { //intercept the values + document.getElementById("jsondata").innerHTML=self.configurationValues; + } else { //pass them silently + GBjs.sendAppMessage(JSON.stringify(dict)); + } return callbackAck; } catch (e) { @@ -179,8 +183,8 @@ function gbPebble() { if (str.split(needle)[1] !== undefined) { var t = new Object(); t.response = decodeURIComponent(str.split(needle)[1]); - self.evaluate('webviewclosed',[t]); showStep("step2"); + self.evaluate('webviewclosed',[t]); } else { console.error("No valid configuration found in the entered string."); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index bc3fd2026..6995799e5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -140,6 +140,11 @@ class PebbleIoThread extends GBDeviceIoThread { } }; + private void sendAppMessageJS(GBDeviceEventAppMessage appMessage) { + WebViewSingleton.getorInitWebView(getContext(), gbDevice, appMessage.appUUID); + WebViewSingleton.appMessage(appMessage.message); + } + private void sendAppMessageIntent(GBDeviceEventAppMessage appMessage) { Intent intent = new Intent(); intent.setAction(PEBBLEKIT_ACTION_APP_RECEIVE); @@ -582,6 +587,7 @@ class PebbleIoThread extends GBDeviceIoThread { setInstallSlot(appInfoEvent.freeSlot); return false; } else if (deviceEvent instanceof GBDeviceEventAppMessage) { + sendAppMessageJS((GBDeviceEventAppMessage) deviceEvent); if (mEnablePebblekit) { LOG.info("Got AppMessage event"); sendAppMessageIntent((GBDeviceEventAppMessage) deviceEvent); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/WebViewSingleton.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/WebViewSingleton.java index f1a8a58cb..8a2786f3e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/WebViewSingleton.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/WebViewSingleton.java @@ -19,6 +19,7 @@ import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; @@ -32,6 +33,7 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; import java.util.Iterator; import java.util.Scanner; import java.util.UUID; @@ -107,18 +109,22 @@ public class WebViewSingleton extends Activity { } public static void appMessage(final String message) { + + final String appMessage = jsInterface.parseIncomingAppMessage(message); + LOG.debug("to WEBVIEW: " + appMessage); + new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - instance.evaluateJavascript("Pebble.evaluate('appmessage',[{'payload':" + message + "}]);", new ValueCallback() { + instance.evaluateJavascript("Pebble.evaluate('appmessage',[" + appMessage + "]);", new ValueCallback() { @Override public void onReceiveValue(String s) { LOG.debug("Callback from showConfiguration", s); } }); } else { - instance.loadUrl("javascript:Pebble.evaluate('appmessage',[{'payload':" + message + "}]);"); + instance.loadUrl("javascript:Pebble.evaluate('appmessage',[" + appMessage + "]);"); } } }); @@ -129,6 +135,13 @@ public class WebViewSingleton extends Activity { @Override public void run() { if (instance != null) { + instance.setWebChromeClient(null); + instance.setWebViewClient(null); + instance.clearHistory(); + instance.clearCache(true); + instance.loadUrl("about:blank"); + instance.freeMemory(); + instance.pauseTimers(); instance.destroy(); instance = null; contextWrapper = null; @@ -202,6 +215,48 @@ public class WebViewSingleton extends Activity { this.mUuid = mUuid; } + public String parseIncomingAppMessage(String msg) { + JSONObject jsAppMessage = new JSONObject(); + + JSONObject knownKeys = getAppConfigurationKeys(this.mUuid); + HashMap appKeysMap = new HashMap(); + + String inKey, outKey; + //knownKeys contains "name"->"index", we need to reverse that + for (Iterator key = knownKeys.keys(); key.hasNext(); ) { + inKey = key.next(); + appKeysMap.put(knownKeys.optInt(inKey), inKey); + } + + try { + JSONArray incoming = new JSONArray(msg); + JSONObject outgoing = new JSONObject(); + for (int i = 0; i < incoming.length(); i++) { + JSONObject in = incoming.getJSONObject(i); + outKey = null; + Object outValue = null; + for (Iterator key = in.keys(); key.hasNext(); ) { + inKey = key.next(); + switch (inKey) { + case "key": + outKey = appKeysMap.get(in.optInt(inKey)); + break; + case "value": + outValue = in.get(inKey); + } + } + if (outKey != null && outValue != null) { + outgoing.put(outKey, outValue); + } + } + jsAppMessage.put("payload", outgoing); + + } catch (JSONException e) { + e.printStackTrace(); + } + return jsAppMessage.toString(); + } + @JavascriptInterface public void gbLog(String msg) { LOG.debug("WEBVIEW", msg);