mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-03 17:02:13 +01:00
Pebble background webview improvements:
remove the pre-KITKAT checks as the minsupportedversion is KITKAT fix the currentPosition override move the returned configuration parsing to onResume method (where it was previously) as it seems more reliable pass the whole GBDeviceEventAppMessage object, this way the jsInterface in the webview doesn't need to be static anymore change the way the webview is initialized, this way the context doesn't need to be static anymore use runOnUiThread instead of the Handler .. MainLooper to post the commands to the webview instance comment a couple of custom message handler for weather as the watchapp seem to work well with JS alone add a couple of log messages for debugging known issue: legacy app configuration pasting does not work.
This commit is contained in:
parent
593b169f00
commit
76be0ae676
@ -1,7 +1,5 @@
|
||||
navigator.geolocation.getCurrentPosition = function(success, failure) { //override because default implementation requires GPS permission
|
||||
success(JSON.parse(GBjs.getCurrentPosition()));
|
||||
failure({ code: 2, message: "POSITION_UNAVAILABLE"});
|
||||
|
||||
success(JSON.parse(GBjs.getCurrentPosition()))
|
||||
}
|
||||
|
||||
if (window.Storage){
|
||||
|
@ -3,7 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.view.MenuItem;
|
||||
@ -61,41 +60,14 @@ public class ExternalPebbleJSActivity extends GBActivity {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
// chromium, enable hardware acceleration
|
||||
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
} else {
|
||||
// older android version, disable hardware acceleration
|
||||
v.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
|
||||
|
||||
String queryString = "";
|
||||
if (confUri != null) {
|
||||
//getting back with configuration data
|
||||
try {
|
||||
appUuid = UUID.fromString(confUri.getHost());
|
||||
queryString = confUri.getEncodedQuery();
|
||||
} catch (IllegalArgumentException e) {
|
||||
GB.toast("returned uri: " + confUri.toString(), Toast.LENGTH_LONG, GB.ERROR);
|
||||
}
|
||||
((WebView) v).loadUrl("file:///android_asset/app_config/configure.html?" + queryString);
|
||||
} else {
|
||||
//show configuration
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
myWebView.evaluateJavascript("Pebble.evaluate('showConfiguration');", new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String s) {
|
||||
LOG.debug("Callback from showConfiguration", s);
|
||||
LOG.debug("Callback from showConfiguration: " + s);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
((WebView) v).loadUrl("javascript:Pebble.evaluate('showConfiguration');");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,6 +80,22 @@ public class ExternalPebbleJSActivity extends GBActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
String queryString = "";
|
||||
if (confUri != null) {
|
||||
//getting back with configuration data
|
||||
LOG.debug("WEBVIEW returned config: " + confUri.toString());
|
||||
try {
|
||||
appUuid = UUID.fromString(confUri.getHost());
|
||||
queryString = confUri.getEncodedQuery();
|
||||
} catch (IllegalArgumentException e) {
|
||||
GB.toast("returned uri: " + confUri.toString(), Toast.LENGTH_LONG, GB.ERROR);
|
||||
}
|
||||
myWebView.loadUrl("file:///android_asset/app_config/configure.html?" + queryString);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onNewIntent(Intent incoming) {
|
||||
incoming.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
|
@ -82,8 +82,7 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
private int mBytesWritten = -1;
|
||||
|
||||
private void sendAppMessageJS(GBDeviceEventAppMessage appMessage) {
|
||||
// WebViewSingleton.runJavascriptInterface(gbDevice, appMessage.appUUID);
|
||||
WebViewSingleton.appMessage(appMessage.message);
|
||||
WebViewSingleton.appMessage(appMessage);
|
||||
write(mPebbleProtocol.encodeApplicationMessageAck(appMessage.appUUID, (byte) appMessage.id));
|
||||
}
|
||||
|
||||
|
@ -385,16 +385,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||
super(device);
|
||||
mAppMessageHandlers.put(UUID_MORPHEUZ, new AppMessageHandlerMorpheuz(UUID_MORPHEUZ, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_MISFIT, new AppMessageHandlerMisfit(UUID_MISFIT, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_PEBBLE_TIMESTYLE, new AppMessageHandlerTimeStylePebble(UUID_PEBBLE_TIMESTYLE, PebbleProtocol.this));
|
||||
//mAppMessageHandlers.put(UUID_PEBSTYLE, new AppMessageHandlerPebStyle(UUID_PEBSTYLE, PebbleProtocol.this));
|
||||
//mAppMessageHandlers.put(UUID_MARIOTIME, new AppMessageHandlerMarioTime(UUID_MARIOTIME, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_HELTHIFY, new AppMessageHandlerHealthify(UUID_HELTHIFY, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_TREKVOLLE, new AppMessageHandlerTrekVolle(UUID_TREKVOLLE, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_SQUARE, new AppMessageHandlerSquare(UUID_SQUARE, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_ZALEWSZCZAK_CROWEX, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_CROWEX, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_ZALEWSZCZAK_FANCY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_FANCY, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_ZALEWSZCZAK_TALLY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_TALLY, PebbleProtocol.this));
|
||||
mAppMessageHandlers.put(UUID_OBSIDIAN, new AppMessageHandlerObsidian(UUID_OBSIDIAN, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_SQUARE, new AppMessageHandlerSquare(UUID_SQUARE, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_ZALEWSZCZAK_CROWEX, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_CROWEX, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_ZALEWSZCZAK_FANCY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_FANCY, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_ZALEWSZCZAK_TALLY, new AppMessageHandlerZalewszczak(UUID_ZALEWSZCZAK_TALLY, PebbleProtocol.this));
|
||||
// mAppMessageHandlers.put(UUID_OBSIDIAN, new AppMessageHandlerObsidian(UUID_OBSIDIAN, PebbleProtocol.this));
|
||||
}
|
||||
|
||||
private final HashMap<Byte, DatalogSession> mDatalogSessions = new HashMap<>();
|
||||
|
@ -1,19 +1,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.MutableContextWrapper;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.webkit.ConsoleMessage;
|
||||
@ -52,6 +48,7 @@ import java.util.Scanner;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
@ -61,16 +58,16 @@ public class WebViewSingleton {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebViewSingleton.class);
|
||||
|
||||
private static WebView instance = null;
|
||||
private static JSInterface jsInterface;
|
||||
private static MutableContextWrapper contextWrapper = null;
|
||||
private Activity contextWrapper;
|
||||
private static WebViewSingleton webViewSingleton = new WebViewSingleton();
|
||||
|
||||
private WebViewSingleton() {
|
||||
}
|
||||
|
||||
public static synchronized WebView createWebView(Context context) {
|
||||
public static synchronized WebView createWebView(Activity context) {
|
||||
if (instance == null) {
|
||||
contextWrapper = new MutableContextWrapper(context);
|
||||
instance = new WebView(contextWrapper);
|
||||
webViewSingleton.contextWrapper = context;
|
||||
instance = new WebView(context);
|
||||
instance.setWillNotDraw(true);
|
||||
instance.clearCache(true);
|
||||
instance.setWebViewClient(new GBWebClient());
|
||||
@ -86,9 +83,9 @@ public class WebViewSingleton {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void updateActivityContext(Context context) {
|
||||
public static void updateActivityContext(Activity context) {
|
||||
if (context instanceof Activity) {
|
||||
contextWrapper.setBaseContext(context);
|
||||
webViewSingleton.contextWrapper = context;
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,50 +94,46 @@ public class WebViewSingleton {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void runJavascriptInterface(final GBDevice device, final UUID uuid) {
|
||||
if (jsInterface == null || !device.equals(jsInterface.device) || !uuid.equals(jsInterface.mUuid)) {
|
||||
jsInterface = new JSInterface(device, uuid);
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
public static void runJavascriptInterface(GBDevice device, UUID uuid) {
|
||||
|
||||
final JSInterface jsInterface = new JSInterface(device, uuid);
|
||||
|
||||
webViewSingleton.contextWrapper.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
instance.removeJavascriptInterface("GBjs");
|
||||
instance.addJavascriptInterface(jsInterface, "GBjs");
|
||||
instance.loadUrl("file:///android_asset/app_config/configure.html");
|
||||
instance.loadUrl("file:///android_asset/app_config/configure.html?rand=" + Math.random() * 500);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
LOG.debug("Not replacing the JS in the webview. JS uuid " + jsInterface.mUuid.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void appMessage(String message) {
|
||||
public static void appMessage(GBDeviceEventAppMessage message) {
|
||||
|
||||
if (instance == null)
|
||||
if (instance == null) {
|
||||
LOG.warn("WEBVIEW is not initialized, cannot send appMessages to it");
|
||||
return;
|
||||
}
|
||||
|
||||
final String appMessage = jsInterface.parseIncomingAppMessage(message);
|
||||
final String appMessage = parseIncomingAppMessage(message.message, message.appUUID);
|
||||
LOG.debug("to WEBVIEW: " + appMessage);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
webViewSingleton.contextWrapper.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
instance.evaluateJavascript("Pebble.evaluate('appmessage',[" + appMessage + "]);", new ValueCallback<String>() {
|
||||
@Override
|
||||
public void onReceiveValue(String s) {
|
||||
//TODO: the message should be acked here instead of in PebbleIoThread
|
||||
LOG.debug("Callback from appmessage", s);
|
||||
LOG.debug("Callback from appmessage: " + s);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
instance.loadUrl("javascript:Pebble.evaluate('appmessage',[" + appMessage + "]);");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void disposeWebView() {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
webViewSingleton.contextWrapper.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (instance != null) {
|
||||
@ -154,7 +147,7 @@ public class WebViewSingleton {
|
||||
// instance.destroy();
|
||||
// instance = null;
|
||||
// contextWrapper = null;
|
||||
jsInterface = null;
|
||||
// jsInterface = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -173,9 +166,9 @@ public class WebViewSingleton {
|
||||
|
||||
this.timestamp = (System.currentTimeMillis() / 1000) - 86400; //let accessor know this value is really old
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(contextWrapper, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
|
||||
if (ActivityCompat.checkSelfPermission(webViewSingleton.contextWrapper, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
|
||||
prefs.getBoolean("use_updated_location_if_available", false)) {
|
||||
LocationManager locationManager = (LocationManager) contextWrapper.getSystemService(Context.LOCATION_SERVICE);
|
||||
LocationManager locationManager = (LocationManager) webViewSingleton.contextWrapper.getSystemService(Context.LOCATION_SERVICE);
|
||||
Criteria criteria = new Criteria();
|
||||
String provider = locationManager.getBestProvider(criteria, false);
|
||||
if (provider != null) {
|
||||
@ -197,11 +190,18 @@ public class WebViewSingleton {
|
||||
}
|
||||
}
|
||||
|
||||
private static WebResourceResponse mimicKiezelPayResponse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static WebResourceResponse mimicOpenWeatherMapResponse() {
|
||||
WeatherSpec weatherSpec = Weather.getInstance().getWeatherSpec();
|
||||
|
||||
if (weatherSpec == null) return null;
|
||||
if (weatherSpec == null) {
|
||||
LOG.warn("WEBVIEW - Weather instance is null, cannot update weather");
|
||||
return null;
|
||||
}
|
||||
//location block
|
||||
|
||||
CurrentPosition currentPosition = new CurrentPosition();
|
||||
@ -276,25 +276,26 @@ public class WebViewSingleton {
|
||||
}
|
||||
|
||||
private static class GBWebClient extends WebViewClient {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
LOG.debug("WEBVIEW shouldInterceptRequest URL" + request.getUrl());
|
||||
if (request.getUrl().toString().startsWith("http://api.openweathermap.org") || request.getUrl().toString().startsWith("https://api.openweathermap.org")) {
|
||||
return mimicOpenWeatherMapResponse();
|
||||
} else {
|
||||
LOG.debug("WEBVIEW request:" + request.getUrl().toString() + " denied");
|
||||
LOG.debug("WEBVIEW request:" + request.getUrl().toString() + " not intercepted");
|
||||
}
|
||||
}
|
||||
return super.shouldInterceptRequest(view, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||
LOG.debug("WEBVIEW shouldInterceptRequest URL" + url);
|
||||
LOG.debug("WEBVIEW shouldInterceptRequest URL (legacy)" + url);
|
||||
if (url.startsWith("http://api.openweathermap.org") || url.startsWith("https://api.openweathermap.org")) {
|
||||
return mimicOpenWeatherMapResponse();
|
||||
} else {
|
||||
LOG.debug("WEBVIEW request:" + url + " denied");
|
||||
LOG.debug("WEBVIEW request:" + url + " not intercepted");
|
||||
}
|
||||
return super.shouldInterceptRequest(view, url);
|
||||
}
|
||||
@ -304,7 +305,7 @@ public class WebViewSingleton {
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
contextWrapper.startActivity(i);
|
||||
webViewSingleton.contextWrapper.startActivity(i);
|
||||
} else {
|
||||
url = url.replaceFirst("^pebblejs://close#", "file:///android_asset/app_config/configure.html?config=true&json=");
|
||||
view.loadUrl(url);
|
||||
@ -314,7 +315,6 @@ public class WebViewSingleton {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static JSONObject getAppConfigurationKeys(UUID uuid) {
|
||||
try {
|
||||
File destDir = new File(FileUtils.getExternalFilesDir() + "/pbw-cache");
|
||||
@ -330,21 +330,10 @@ public class WebViewSingleton {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class JSInterface {
|
||||
|
||||
UUID mUuid;
|
||||
GBDevice device;
|
||||
|
||||
public JSInterface(GBDevice device, UUID mUuid) {
|
||||
LOG.debug("Creating JS interface for UUID: " + mUuid.toString());
|
||||
this.device = device;
|
||||
this.mUuid = mUuid;
|
||||
}
|
||||
|
||||
public String parseIncomingAppMessage(String msg) {
|
||||
public static String parseIncomingAppMessage(String msg, UUID uuid) {
|
||||
JSONObject jsAppMessage = new JSONObject();
|
||||
|
||||
JSONObject knownKeys = getAppConfigurationKeys(this.mUuid);
|
||||
JSONObject knownKeys = getAppConfigurationKeys(uuid);
|
||||
HashMap<Integer, String> appKeysMap = new HashMap<Integer, String>();
|
||||
|
||||
String inKey, outKey;
|
||||
@ -383,6 +372,17 @@ public class WebViewSingleton {
|
||||
return jsAppMessage.toString();
|
||||
}
|
||||
|
||||
private static class JSInterface {
|
||||
|
||||
UUID mUuid;
|
||||
GBDevice device;
|
||||
|
||||
public JSInterface(GBDevice device, UUID mUuid) {
|
||||
LOG.debug("Creating JS interface for UUID: " + mUuid.toString());
|
||||
this.device = device;
|
||||
this.mUuid = mUuid;
|
||||
}
|
||||
|
||||
|
||||
private boolean isLocationEnabledForWatchApp() {
|
||||
return true; //as long as we don't give watchapp internet access it's not a problem
|
||||
@ -390,7 +390,7 @@ public class WebViewSingleton {
|
||||
|
||||
@JavascriptInterface
|
||||
public void gbLog(String msg) {
|
||||
LOG.debug("WEBVIEW", msg);
|
||||
LOG.debug("WEBVIEW webpage log", msg);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
@ -457,6 +457,7 @@ public class WebViewSingleton {
|
||||
|
||||
@JavascriptInterface
|
||||
public String getAppConfigurationFile() {
|
||||
LOG.debug("WEBVIEW loading config file of " + this.mUuid.toString());
|
||||
try {
|
||||
File destDir = new File(FileUtils.getExternalFilesDir() + "/pbw-cache");
|
||||
File configurationFile = new File(destDir, this.mUuid.toString() + "_config.js");
|
||||
|
Loading…
Reference in New Issue
Block a user