mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-03-14 10:10:07 +01:00
Improvements to the singleton pattern, better encapsulate fields
This commit is contained in:
parent
f39b11974d
commit
d2c952ffa5
@ -133,7 +133,7 @@ public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
||||
if (showConfig) {
|
||||
Objects.requireNonNull(currentDevice, "Must provide a device when invoking this activity");
|
||||
Objects.requireNonNull(currentUUID, "Must provide a uuid when invoking this activity");
|
||||
WebViewSingleton.runJavascriptInterface(this, currentDevice, currentUUID);
|
||||
WebViewSingleton.getInstance().runJavascriptInterface(this, currentDevice, currentUUID);
|
||||
}
|
||||
|
||||
// FIXME: is this really supposed to be outside the check for SHOW_CONFIG?
|
||||
@ -156,7 +156,7 @@ public class ExternalPebbleJSActivity extends AbstractGBActivity {
|
||||
|
||||
private void setupBGWebView() {
|
||||
setContentView(R.layout.activity_external_pebble_js);
|
||||
myWebView = WebViewSingleton.getWebView(this);
|
||||
myWebView = WebViewSingleton.getInstance().getWebView(this);
|
||||
if (myWebView.getParent() != null) {
|
||||
((ViewGroup) myWebView.getParent()).removeView(myWebView);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
public static void sendAppMessage(GBDeviceEventAppMessage message) {
|
||||
final String jsEvent;
|
||||
try {
|
||||
WebViewSingleton.checkAppRunning(message.appUUID);
|
||||
WebViewSingleton.getInstance().checkAppRunning(message.appUUID);
|
||||
} catch (IllegalStateException ex) {
|
||||
LOG.warn("Unable to send app message: " + message, ex);
|
||||
return;
|
||||
@ -126,7 +126,7 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
|
||||
final String appMessage = PebbleUtils.parseIncomingAppMessage(message.message, message.appUUID, message.id);
|
||||
LOG.debug("to WEBVIEW: event: " + jsEvent + " message: " + appMessage);
|
||||
WebViewSingleton.invokeWebview(new WebViewSingleton.WebViewRunnable() {
|
||||
WebViewSingleton.getInstance().invokeWebview(new WebViewSingleton.WebViewRunnable() {
|
||||
@Override
|
||||
public void invoke(WebView webView) {
|
||||
webView.evaluateJavascript("if (typeof Pebble == 'object') Pebble.evaluate('" + jsEvent + "',[" + appMessage + "]);", new ValueCallback<String>() {
|
||||
@ -424,7 +424,7 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
}
|
||||
|
||||
if (GBApplication.getGBPrefs().isBackgroundJsEnabled()) {
|
||||
WebViewSingleton.disposeWebView();
|
||||
WebViewSingleton.getInstance().disposeWebView();
|
||||
}
|
||||
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
@ -553,9 +553,9 @@ class PebbleIoThread extends GBDeviceIoThread {
|
||||
LOG.info("got GBDeviceEventAppManagement START event for uuid: " + appMgmt.uuid);
|
||||
if (GBApplication.getGBPrefs().isBackgroundJsEnabled()) {
|
||||
if (mPebbleProtocol.hasAppMessageHandler(appMgmt.uuid)) {
|
||||
WebViewSingleton.stopJavascriptInterface();
|
||||
WebViewSingleton.getInstance().stopJavascriptInterface();
|
||||
} else {
|
||||
WebViewSingleton.runJavascriptInterface(gbDevice, appMgmt.uuid);
|
||||
WebViewSingleton.getInstance().runJavascriptInterface(gbDevice, appMgmt.uuid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -41,16 +41,10 @@ import java.io.ByteArrayInputStream;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton.internetHelper;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton.internetHelperBound;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton.internetHelperListener;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton.internetResponse;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton.latch;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.WebViewSingleton;
|
||||
|
||||
public class GBWebClient extends WebViewClient {
|
||||
|
||||
@ -85,19 +79,14 @@ public class GBWebClient extends WebViewClient {
|
||||
|
||||
private WebResourceResponse mimicReply(Uri requestedUri) {
|
||||
if (requestedUri.getHost() != null && (StringUtils.indexOfAny(requestedUri.getHost(), AllowedDomains) != -1)) {
|
||||
if (GBApplication.getGBPrefs().isBackgroundJsEnabled() && internetHelperBound) {
|
||||
if (GBApplication.getGBPrefs().isBackgroundJsEnabled() && WebViewSingleton.getInstance().internetHelperBound) {
|
||||
LOG.debug("WEBVIEW forwarding request to the internet helper");
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("URL", requestedUri.toString());
|
||||
Message webRequest = Message.obtain();
|
||||
webRequest.replyTo = internetHelperListener;
|
||||
webRequest.setData(bundle);
|
||||
try {
|
||||
latch = new CountDownLatch(1); //the messenger should run on a single thread, hence we don't need to be worried about concurrency. This approach however is certainly not ideal.
|
||||
internetHelper.send(webRequest);
|
||||
latch.await();
|
||||
return internetResponse;
|
||||
|
||||
return WebViewSingleton.getInstance().send(webRequest);
|
||||
} catch (RemoteException | InterruptedException e) {
|
||||
LOG.warn("Error downloading data from " + requestedUri, e);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
@ -54,33 +55,33 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.JSInt
|
||||
public class WebViewSingleton {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebViewSingleton.class);
|
||||
private static WebViewSingleton instance = new WebViewSingleton();
|
||||
|
||||
private WebView instance = null;
|
||||
private WebView webView = null;
|
||||
private MutableContextWrapper contextWrapper;
|
||||
private Looper mainLooper;
|
||||
private static WebViewSingleton webViewSingleton = new WebViewSingleton();
|
||||
private static UUID currentRunningUUID;
|
||||
public static Messenger internetHelper = null;
|
||||
public static boolean internetHelperBound;
|
||||
public static CountDownLatch latch;
|
||||
public static WebResourceResponse internetResponse;
|
||||
public static Messenger internetHelperListener;
|
||||
private static boolean internetHelperInstalled;
|
||||
private UUID currentRunningUUID;
|
||||
private Messenger internetHelper = null;
|
||||
public boolean internetHelperBound;
|
||||
private boolean internetHelperInstalled;
|
||||
private CountDownLatch latch;
|
||||
private WebResourceResponse internetResponse;
|
||||
private Messenger internetHelperListener;
|
||||
|
||||
private WebViewSingleton() {
|
||||
}
|
||||
|
||||
public static synchronized void ensureCreated(Activity context) {
|
||||
if (webViewSingleton.instance == null) {
|
||||
webViewSingleton.contextWrapper = new MutableContextWrapper(context);
|
||||
webViewSingleton.mainLooper = webViewSingleton.contextWrapper.getMainLooper();
|
||||
webViewSingleton.instance = new WebView(webViewSingleton.contextWrapper);
|
||||
if (instance.webView == null) {
|
||||
instance.contextWrapper = new MutableContextWrapper(context);
|
||||
instance.mainLooper = context.getMainLooper();
|
||||
instance.webView = new WebView(instance.contextWrapper);
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
webViewSingleton.instance.setWillNotDraw(true);
|
||||
webViewSingleton.instance.clearCache(true);
|
||||
webViewSingleton.instance.setWebViewClient(new GBWebClient());
|
||||
webViewSingleton.instance.setWebChromeClient(new GBChromeClient());
|
||||
WebSettings webSettings = webViewSingleton.instance.getSettings();
|
||||
instance.webView.setWillNotDraw(true);
|
||||
instance.webView.clearCache(true);
|
||||
instance.webView.setWebViewClient(new GBWebClient());
|
||||
instance.webView.setWebChromeClient(new GBChromeClient());
|
||||
WebSettings webSettings = instance.webView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
//needed to access the DOM
|
||||
webSettings.setDomStorageEnabled(true);
|
||||
@ -90,7 +91,7 @@ public class WebViewSingleton {
|
||||
}
|
||||
|
||||
//Internet helper outgoing connection
|
||||
private static ServiceConnection internetHelperConnection = new ServiceConnection() {
|
||||
private ServiceConnection internetHelperConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
LOG.info("internet helper service bound");
|
||||
internetHelperBound = true;
|
||||
@ -104,8 +105,20 @@ public class WebViewSingleton {
|
||||
}
|
||||
};
|
||||
|
||||
public static WebViewSingleton getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public WebResourceResponse send(Message webRequest) throws RemoteException, InterruptedException {
|
||||
webRequest.replyTo = internetHelperListener;
|
||||
latch = new CountDownLatch(1); //the messenger should run on a single thread, hence we don't need to be worried about concurrency. This approach however is certainly not ideal.
|
||||
internetHelper.send(webRequest);
|
||||
latch.await();
|
||||
return internetResponse;
|
||||
}
|
||||
|
||||
//Internet helper inbound (responses) handler
|
||||
private static class IncomingHandler extends Handler {
|
||||
private class IncomingHandler extends Handler {
|
||||
|
||||
private String getCharsetFromHeaders(String contentType) {
|
||||
if (contentType != null && contentType.toLowerCase().trim().contains("charset=")) {
|
||||
@ -137,9 +150,9 @@ public class WebViewSingleton {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static WebView getWebView(Context context) {
|
||||
webViewSingleton.contextWrapper.setBaseContext(context);
|
||||
return webViewSingleton.instance;
|
||||
public WebView getWebView(Context context) {
|
||||
contextWrapper.setBaseContext(context);
|
||||
return webView;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,23 +160,21 @@ public class WebViewSingleton {
|
||||
* @param uuid the uuid of the application expected to be running
|
||||
* @throws IllegalStateException when the webview is not active or the app is not running
|
||||
*/
|
||||
public static void checkAppRunning(@NonNull UUID uuid) {
|
||||
if (webViewSingleton.instance == null) {
|
||||
throw new IllegalStateException("webViewSingleton.instance is null!");
|
||||
public void checkAppRunning(@NonNull UUID uuid) {
|
||||
if (webView == null) {
|
||||
throw new IllegalStateException("instance.webView is null!");
|
||||
}
|
||||
if (!uuid.equals(currentRunningUUID)) {
|
||||
throw new IllegalStateException("Expected app " + uuid + " is not running, but " + currentRunningUUID + " is.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void runJavascriptInterface(@NonNull Activity context, @NonNull GBDevice device, @NonNull UUID uuid) {
|
||||
if (webViewSingleton.instance == null || webViewSingleton.contextWrapper == null) {
|
||||
ensureCreated(context);
|
||||
}
|
||||
public void runJavascriptInterface(@NonNull Activity context, @NonNull GBDevice device, @NonNull UUID uuid) {
|
||||
ensureCreated(context);
|
||||
runJavascriptInterface(device, uuid);
|
||||
}
|
||||
|
||||
public static void runJavascriptInterface(@NonNull GBDevice device, @NonNull UUID uuid) {
|
||||
public void runJavascriptInterface(@NonNull GBDevice device, @NonNull UUID uuid) {
|
||||
if (uuid.equals(currentRunningUUID)) {
|
||||
LOG.debug("WEBVIEW uuid not changed keeping the old context");
|
||||
} else {
|
||||
@ -183,10 +194,10 @@ public class WebViewSingleton {
|
||||
String internetHelperPkg = "nodomain.freeyourgadget.internethelper";
|
||||
String internetHelperCls = internetHelperPkg + ".MyService";
|
||||
try {
|
||||
webViewSingleton.contextWrapper.getPackageManager().getApplicationInfo(internetHelperPkg, 0);
|
||||
contextWrapper.getPackageManager().getApplicationInfo(internetHelperPkg, 0);
|
||||
Intent intent = new Intent();
|
||||
intent.setComponent(new ComponentName(internetHelperPkg, internetHelperCls));
|
||||
webViewSingleton.contextWrapper.getApplicationContext().bindService(intent, internetHelperConnection, Context.BIND_AUTO_CREATE);
|
||||
contextWrapper.getApplicationContext().bindService(intent, internetHelperConnection, Context.BIND_AUTO_CREATE);
|
||||
internetHelperListener = new Messenger(new IncomingHandler());
|
||||
internetHelperInstalled = true;
|
||||
}
|
||||
@ -196,10 +207,9 @@ public class WebViewSingleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void stopJavascriptInterface() {
|
||||
public void stopJavascriptInterface() {
|
||||
invokeWebview(new WebViewRunnable() {
|
||||
@Override
|
||||
public void invoke(WebView webView) {
|
||||
@ -209,10 +219,10 @@ public class WebViewSingleton {
|
||||
});
|
||||
}
|
||||
|
||||
public static void disposeWebView() {
|
||||
public void disposeWebView() {
|
||||
if (internetHelperBound) {
|
||||
LOG.debug("WEBVIEW: will unbind the internet helper");
|
||||
webViewSingleton.contextWrapper.getApplicationContext().unbindService(internetHelperConnection);
|
||||
contextWrapper.getApplicationContext().unbindService(internetHelperConnection);
|
||||
internetHelperBound = false;
|
||||
}
|
||||
currentRunningUUID = null;
|
||||
@ -227,34 +237,34 @@ public class WebViewSingleton {
|
||||
webView.loadUrl("about:blank");
|
||||
// webView.freeMemory();
|
||||
webView.pauseTimers();
|
||||
// instance.destroy();
|
||||
// instance = null;
|
||||
// webView.destroy();
|
||||
// webView = null;
|
||||
// contextWrapper = null;
|
||||
// jsInterface = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void invokeWebview(final WebViewRunnable runnable) {
|
||||
if (webViewSingleton.instance == null || webViewSingleton.mainLooper == null) {
|
||||
public void invokeWebview(final WebViewRunnable runnable) {
|
||||
if (webView == null || mainLooper == null) {
|
||||
LOG.warn("Webview already disposed, ignoring runnable");
|
||||
return;
|
||||
}
|
||||
new Handler(webViewSingleton.mainLooper).post(new Runnable() {
|
||||
new Handler(mainLooper).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (webViewSingleton.instance == null) {
|
||||
if (webView == null) {
|
||||
LOG.warn("Webview already disposed, cannot invoke runnable");
|
||||
return;
|
||||
}
|
||||
runnable.invoke(webViewSingleton.instance);
|
||||
runnable.invoke(webView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface WebViewRunnable {
|
||||
/**
|
||||
* Called in the main thread with a non-null webView instance
|
||||
* Called in the main thread with a non-null webView webView
|
||||
* @param webView the webview, never null
|
||||
*/
|
||||
void invoke(WebView webView);
|
||||
|
Loading…
x
Reference in New Issue
Block a user