1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-11-22 12:21:15 +00:00

Improved polling for web gui (fixes #7).

This commit is contained in:
Felix Ableitner 2014-05-15 14:54:21 +02:00
parent a2a3f189b3
commit 7576e2a47d
2 changed files with 109 additions and 29 deletions

View file

@ -8,7 +8,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
@ -30,7 +29,7 @@ import java.io.InputStream;
/**
* Holds a WebView that shows the web ui of the local syncthing instance.
*/
public class WebGuiActivity extends Activity {
public class WebGuiActivity extends Activity implements SyncthingService.OnWebGuiAvailableListener {
private static final String TAG = "WebGuiActivity";
@ -54,6 +53,7 @@ public class WebGuiActivity extends Activity {
public void onServiceConnected(ComponentName className, IBinder service) {
SyncthingServiceBinder binder = (SyncthingServiceBinder) service;
mSyncthingService = binder.getService();
mSyncthingService.registerOnWebGuiAvailableListener(WebGuiActivity.this);
}
public void onServiceDisconnected(ComponentName className) {
@ -62,32 +62,14 @@ public class WebGuiActivity extends Activity {
};
/**
* Retries loading every second until the web UI becomes available.
* Hides the loading screen and shows the WebView once it is fully loaded.
*/
private WebViewClient mWebViewClient = new WebViewClient() {
private int mError = 0;
@Override
public void onReceivedError(WebView view, int errorCode, String description,
String failingUrl) {
mError = errorCode;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mError = 0;
mWebView.loadUrl(SyncthingService.SYNCTHING_URL);
}
}, 1000);
}
@Override
public void onPageFinished(WebView view, String url) {
if (mError == 0) {
mWebView.setVisibility(View.VISIBLE);
mLoadingView.setVisibility(View.GONE);
}
mWebView.setVisibility(View.VISIBLE);
mLoadingView.setVisibility(View.GONE);
}
};
@ -100,11 +82,6 @@ public class WebGuiActivity extends Activity {
@SuppressLint("SetJavaScriptEnabled")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getApplicationContext().startService(
new Intent(this, SyncthingService.class));
getApplicationContext().bindService(
new Intent(this, SyncthingService.class),
mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
setContentView(R.layout.main);
@ -115,7 +92,6 @@ public class WebGuiActivity extends Activity {
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(mWebViewClient);
mWebView.loadUrl(SyncthingService.SYNCTHING_URL);
// Handle first start.
File config = new File(getApplicationInfo().dataDir, CONFIG_FILE);
@ -130,8 +106,23 @@ public class WebGuiActivity extends Activity {
.setNeutralButton(android.R.string.ok, null)
.show();
}
getApplicationContext().startService(
new Intent(this, SyncthingService.class));
getApplicationContext().bindService(
new Intent(this, SyncthingService.class),
mSyncthingServiceConnection, Context.BIND_AUTO_CREATE);
}
/**
* Loads and shows WebView, hides loading view.
*/
@Override
public void onWebGuiAvailable() {
mWebView.loadUrl(SyncthingService.SYNCTHING_URL);
}
@Override
public void onDestroy() {
super.onDestroy();

View file

@ -4,6 +4,7 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
@ -11,10 +12,21 @@ import android.util.Log;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.WebGuiActivity;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
/**
* Holds the native syncthing instance and provides an API to access it.
@ -35,8 +47,26 @@ public class SyncthingService extends Service {
*/
public static final String SYNCTHING_URL = "http://127.0.0.1:8080";
/**
* Interval in ms, at which connections to the web gui are performed on first start
* to find out if it's online.
*/
private static final long WEB_GUI_POLL_INTERVAL = 100;
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
/**
* Callback for when the Syncthing web interface becomes first available after service start.
*/
public interface OnWebGuiAvailableListener {
public void onWebGuiAvailable();
}
private LinkedList<OnWebGuiAvailableListener> mOnWebGuiAvailableListeners =
new LinkedList<OnWebGuiAvailableListener>();
private boolean mIsWebGuiAvailable = false;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
@ -100,6 +130,48 @@ public class SyncthingService extends Service {
}
}
}
/**
* Polls SYNCTHING_URL until it returns HTTP status OK, then calls all listeners
* in mOnWebGuiAvailableListeners and clears it.
*/
private class PollWebGuiAvailableTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
int status = 0;
HttpClient httpclient = new DefaultHttpClient();
HttpHead head = new HttpHead(SYNCTHING_URL);
do {
try {
Thread.sleep(WEB_GUI_POLL_INTERVAL);
HttpResponse response = httpclient.execute(head);
// NOTE: status is not really needed, as HttpHostConnectException is thrown
// earlier.
status = response.getStatusLine().getStatusCode();
}
catch (HttpHostConnectException e) {
// We catch this in every call, as long as the service is not online,
// so we ignore and continue.
}
catch (IOException e) {
Log.d(TAG, "Failed to poll for web interface", e);
}
catch (InterruptedException e) {
Log.d(TAG, "Failed to poll for web interface", e);
}
} while(status != HttpStatus.SC_OK);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
mIsWebGuiAvailable = true;
for (OnWebGuiAvailableListener listener : mOnWebGuiAvailableListeners) {
listener.onWebGuiAvailable();
}
mOnWebGuiAvailableListeners.clear();
}
}
/**
* Creates notification, starts native binary.
@ -118,6 +190,8 @@ public class SyncthingService extends Service {
startForeground(NOTIFICATION_ID, n);
new Thread(new NativeSyncthingRunnable()).start();
new PollWebGuiAvailableTask().execute();
}
@Override
@ -134,4 +208,19 @@ public class SyncthingService extends Service {
new PostTask().execute(PostTask.URI_SHUTDOWN);
}
/**
* Register a listener for the web gui becoming available..
*
* If the web gui is already available, listener will be called immediately.
* Listeners are unregistered automatically after being called.
*/
public void registerOnWebGuiAvailableListener(OnWebGuiAvailableListener listener) {
if (mIsWebGuiAvailable) {
listener.onWebGuiAvailable();
}
else {
mOnWebGuiAvailableListeners.addLast(listener);
}
}
}