Pebble: refactor the background webview

Now native controls seem to work (including datepicker), still the webview is not started upon watchapp start, but when long-pressing each app in the app manager. After the webview is started it will live in the background until device disconnect.
This commit is contained in:
Daniele Gobbetti 2017-01-01 18:33:39 +01:00
parent 6d02a76328
commit eaaa940637
4 changed files with 103 additions and 102 deletions

View File

@ -7,6 +7,7 @@ import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebView;
@ -45,11 +46,64 @@ public class ExternalPebbleJSActivity extends GBActivity {
throw new IllegalArgumentException("Must provide a device when invoking this activity");
}
setContentView(R.layout.activity_external_pebble_js);
myWebView = WebViewSingleton.getorInitWebView(this, mGBDevice, appUuid);
myWebView.setWillNotDraw(false);
myWebView.addJavascriptInterface(new ActivityJSInterface(ExternalPebbleJSActivity.this), "GBActivity");
FrameLayout fl = (FrameLayout) findViewById(R.id.webview_placeholder);
fl.addView(myWebView);
WebViewSingleton.getorInitWebView(this, mGBDevice, appUuid);
myWebView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@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);
}
});
} else {
((WebView) v).loadUrl("javascript:Pebble.evaluate('showConfiguration');");
}
}
}
@Override
public void onViewDetachedFromWindow(View v) {
myWebView.removeJavascriptInterface("GBActivity");
myWebView.setWillNotDraw(true);
FrameLayout fl = (FrameLayout) findViewById(R.id.webview_placeholder);
fl.removeAllViews();
}
});
}
@ -60,57 +114,6 @@ public class ExternalPebbleJSActivity extends GBActivity {
confUri = incoming.getData();
}
@Override
protected void onResume() {
super.onResume();
String queryString = "";
myWebView = WebViewSingleton.getorInitWebView(this, mGBDevice, appUuid);
myWebView.addJavascriptInterface(new ActivityJSInterface(this), "GBActivity");
FrameLayout fl = (FrameLayout) findViewById(R.id.webview_placeholder);
if (myWebView != null)
fl.addView(myWebView);
//needed to display clay dialogs
myWebView.getSettings().setUseWideViewPort(true);
myWebView.requestFocus();
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);
}
myWebView.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);
}
});
} else {
myWebView.loadUrl("javascript:Pebble.evaluate('showConfiguration');");
}
}
}
@Override
protected void onPause() {
FrameLayout fl = (FrameLayout) findViewById(R.id.webview_placeholder);
fl.removeAllViews();
super.onPause();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {

View File

@ -39,6 +39,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils;
import nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton;
public abstract class AbstractAppManagerFragment extends Fragment {
@ -323,6 +324,8 @@ public abstract class AbstractAppManagerFragment extends Fragment {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
popupMenu.show();
//TODO: replace with local broadcast on app start
WebViewSingleton.getorInitWebView(getActivity(), mGBDevice, selectedApp.getUUID());
return true;
}

View File

@ -570,6 +570,7 @@ class PebbleIoThread extends GBDeviceIoThread {
case START:
LOG.info("got GBDeviceEventAppManagement START event for uuid: " + appMgmt.uuid);
WebViewSingleton.getorInitWebView(getContext(), gbDevice, appMgmt.uuid);
//TODO: the method call above will not work the first time as we need an activity. Either we find a way to have one here, or replace it with a local broadcast
break;
default:
break;

View File

@ -1,12 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.MutableContextWrapper;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.webkit.ConsoleMessage;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
@ -35,7 +33,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class WebViewSingleton {
public class WebViewSingleton extends Activity {
private static final Logger LOG = LoggerFactory.getLogger(WebViewSingleton.class);
@ -46,56 +44,52 @@ public class WebViewSingleton {
private WebViewSingleton() {
}
public static WebView getorInitWebView(final Context context, final GBDevice device, final UUID uuid) {
final MutableContextWrapper _contextWrapper = new MutableContextWrapper(context);
if (contextWrapper != null) {
contextWrapper.setBaseContext(context);
} else {
contextWrapper = _contextWrapper;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (instance == null) {
instance = new WebView(_contextWrapper);
instance.clearCache(true);
instance.setWebViewClient(new GBWebClient());
instance.setWebChromeClient(new GBChromeClient());
instance.setWebContentsDebuggingEnabled(true);
WebSettings webSettings = instance.getSettings();
webSettings.setJavaScriptEnabled(true);
//needed to access the DOM
webSettings.setDomStorageEnabled(true);
//needed for localstorage
webSettings.setDatabaseEnabled(true);
}
if (jsInterface == null || (jsInterface != null && (!device.equals(jsInterface.device) || !uuid.equals(jsInterface.mUuid)))) {
instance.removeJavascriptInterface("GBjs");
jsInterface = new JSInterface(device, uuid);
instance.addJavascriptInterface(jsInterface, "GBjs");
instance.loadUrl("file:///android_asset/app_config/configure.html");
} else {
LOG.debug("Not reloading the webview " + jsInterface.mUuid.toString());
}
public static WebView getorInitWebView(Context context, GBDevice device, UUID uuid) {
if (context instanceof Activity) {
final MutableContextWrapper _contextWrapper = new MutableContextWrapper(context);
if (contextWrapper != null) {
contextWrapper.setBaseContext(context);
} else {
contextWrapper = _contextWrapper;
}
}
//here we are sure that contextWrapper is either null or an activity, hence we run on the main thread
if (contextWrapper != null) {
if (instance == null) {
instance = new WebView(contextWrapper);
instance.setWillNotDraw(true);
instance.clearCache(true);
instance.setWebViewClient(new GBWebClient());
instance.setWebChromeClient(new GBChromeClient());
instance.setWebContentsDebuggingEnabled(true);
WebSettings webSettings = instance.getSettings();
webSettings.setJavaScriptEnabled(true);
//needed to access the DOM
webSettings.setDomStorageEnabled(true);
//needed for localstorage
webSettings.setDatabaseEnabled(true);
}
});
if (jsInterface == null || (jsInterface != null && (!device.equals(jsInterface.device) || !uuid.equals(jsInterface.mUuid)))) {
instance.removeJavascriptInterface("GBjs");
jsInterface = new JSInterface(device, uuid);
instance.addJavascriptInterface(jsInterface, "GBjs");
instance.loadUrl("file:///android_asset/app_config/configure.html");
} else {
LOG.debug("Not reloading the webview " + jsInterface.mUuid.toString());
}
} else {
LOG.debug("WEBV: not using the passed context, as it is not an activity");
}
return instance;
}
public static void disposeWebView() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (instance != null) {
instance.destroy();
instance = null;
}
}
});
if (instance != null) {
instance.destroy();
instance = null;
}
}
private static class GBChromeClient extends WebChromeClient {
@ -155,7 +149,7 @@ public class WebViewSingleton {
@JavascriptInterface
public void gbLog(String msg) {
Log.d("WEBVIEW", msg);
LOG.debug("WEBVIEW", msg);
}
@JavascriptInterface
@ -196,7 +190,7 @@ public class WebViewSingleton {
}
}
LOG.info(out.toString());
LOG.info("WEBV:" + out.toString());
GBApplication.deviceService().onAppConfiguration(this.mUuid, out.toString());
} catch (JSONException e) {