- Add Peers activity
- Save service state - Start router after stopped by system
This commit is contained in:
@ -48,11 +48,17 @@
|
||||
</activity>
|
||||
<activity android:name=".activity.AddressbookActivity"
|
||||
android:label="Address Book"
|
||||
android.theme="@android:style/Theme.NoTitleBar" >
|
||||
android.theme="@android:style/Theme.NoTitleBar"
|
||||
android:launchMode="singleTop" >
|
||||
</activity>
|
||||
<activity android:name=".activity.LogActivity"
|
||||
android:label="Logs"
|
||||
android.theme="@android:style/Theme.NoTitleBar" >
|
||||
</activity>
|
||||
<activity android:name=".activity.PeersActivity"
|
||||
android:label="Peers and Transport Status"
|
||||
android.theme="@android:style/Theme.NoTitleBar"
|
||||
android:launchMode="singleTop" >
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -81,6 +81,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Error Logs"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/peers_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Peers"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
|
20
res/layout/peers.xml
Normal file
20
res/layout/peers.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/peers_status"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="Peers"
|
||||
/>
|
||||
<WebView
|
||||
android:id="@+id/peers_webview"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
@ -82,23 +82,6 @@ public abstract class I2PActivityBase extends Activity {
|
||||
return edit.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the service and bind to it
|
||||
*/
|
||||
protected boolean startRouter() {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
|
||||
System.err.println(this + " calling startService");
|
||||
ComponentName name = startService(intent);
|
||||
if (name == null)
|
||||
System.err.println(this + " XXXXXXXXXXXXXXXXXXXX got from startService: " + name);
|
||||
System.err.println(this + " got from startService: " + name);
|
||||
boolean success = bindRouter(true);
|
||||
if (!success)
|
||||
System.err.println(this + " Bind router failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
@ -197,18 +180,38 @@ public abstract class I2PActivityBase extends Activity {
|
||||
|
||||
////// Service stuff
|
||||
|
||||
/**
|
||||
* Start the service and bind to it
|
||||
*/
|
||||
protected boolean startRouter() {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
|
||||
System.err.println(this + " calling startService");
|
||||
ComponentName name = startService(intent);
|
||||
if (name == null)
|
||||
System.err.println(this + " XXXXXXXXXXXXXXXXXXXX got from startService: " + name);
|
||||
System.err.println(this + " got from startService: " + name);
|
||||
boolean success = bindRouter(true);
|
||||
if (!success)
|
||||
System.err.println(this + " Bind router failed");
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind only
|
||||
*/
|
||||
protected boolean bindRouter(boolean autoCreate) {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
|
||||
System.err.println(this + " calling bindService");
|
||||
_connection = new RouterConnection();
|
||||
boolean success = bindService(intent, _connection, autoCreate ? BIND_AUTO_CREATE : 0);
|
||||
System.err.println(this + " got from bindService: " + success);
|
||||
System.err.println(this + " bindService: auto create? " + autoCreate + " success? " + success);
|
||||
return success;
|
||||
}
|
||||
|
||||
protected void unbindRouter() {
|
||||
if (_isBound) {
|
||||
if (_isBound && _connection != null) {
|
||||
unbindService(_connection);
|
||||
_routerService = null;
|
||||
_isBound = false;
|
||||
@ -220,8 +223,10 @@ public abstract class I2PActivityBase extends Activity {
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
System.err.println(this + " connected to router service");
|
||||
RouterBinder binder = (RouterBinder) service;
|
||||
_routerService = binder.getService();
|
||||
RouterService svc = binder.getService();
|
||||
_routerService = svc;
|
||||
_isBound = true;
|
||||
onRouterBind(svc);
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
@ -229,9 +234,16 @@ public abstract class I2PActivityBase extends Activity {
|
||||
// save memory
|
||||
_routerService = null;
|
||||
_isBound = false;
|
||||
onRouterUnbind();
|
||||
}
|
||||
}
|
||||
|
||||
/** callback from ServiceConnection, override as necessary */
|
||||
protected void onRouterBind(RouterService svc) {}
|
||||
|
||||
/** callback from ServiceConnection, override as necessary */
|
||||
protected void onRouterUnbind() {}
|
||||
|
||||
////// Router stuff
|
||||
|
||||
protected RouterContext getRouterContext() {
|
||||
|
@ -119,6 +119,14 @@ public class MainActivity extends I2PActivityBase {
|
||||
}
|
||||
});
|
||||
|
||||
b = (Button) findViewById(R.id.peers_button);
|
||||
b.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(view.getContext(), PeersActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
b = (Button) findViewById(R.id.router_start_button);
|
||||
b.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
@ -297,6 +305,8 @@ public class MainActivity extends I2PActivityBase {
|
||||
RouterService svc = _routerService;
|
||||
String status =
|
||||
"connected? " + Util.isConnected(this) +
|
||||
"\nMemory: " + DataHelper.formatSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) +
|
||||
"B / " + DataHelper.formatSize(Runtime.getRuntime().maxMemory()) + 'B' +
|
||||
"\nhave ctx? " + (ctx != null) +
|
||||
"\nhave svc? " + (svc != null) +
|
||||
"\nis bound? " + _isBound +
|
||||
|
90
src/net/i2p/android/router/activity/PeersActivity.java
Normal file
90
src/net/i2p/android/router/activity/PeersActivity.java
Normal file
@ -0,0 +1,90 @@
|
||||
package net.i2p.android.router.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.i2p.android.router.R;
|
||||
import net.i2p.android.router.service.RouterService;
|
||||
import net.i2p.router.CommSystemFacade;
|
||||
|
||||
public class PeersActivity extends I2PActivityBase {
|
||||
|
||||
private I2PWebViewClient _wvClient;
|
||||
|
||||
// TODO add some inline style
|
||||
private static final String HEADER = "<html><head></head><body>";
|
||||
private static final String FOOTER = "</body></html>";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.peers);
|
||||
WebView wv = (WebView) findViewById(R.id.peers_webview);
|
||||
wv.getSettings().setLoadsImagesAutomatically(false);
|
||||
// http://stackoverflow.com/questions/2369310/webview-double-tap-zoom-not-working-on-a-motorola-droid-a855
|
||||
wv.getSettings().setUseWideViewPort(true);
|
||||
_wvClient = new I2PWebViewClient();
|
||||
wv.setWebViewClient(_wvClient);
|
||||
wv.getSettings().setBuiltInZoomControls(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Not bound by the time onResume() is called, so we have to do it here.
|
||||
* If it is bound we update twice.
|
||||
*/
|
||||
@Override
|
||||
protected void onRouterBind(RouterService svc) {
|
||||
update();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
WebView wv = (WebView) findViewById(R.id.peers_webview);
|
||||
CommSystemFacade comm = getCommSystem();
|
||||
String data;
|
||||
if (comm != null) {
|
||||
StringWriter out = new StringWriter(32*1024);
|
||||
out.append(HEADER);
|
||||
try {
|
||||
comm.renderStatusHTML(out, "http://thiswontwork.i2p/peers", 0);
|
||||
out.append(FOOTER);
|
||||
data = out.toString();
|
||||
} catch (IOException ioe) {
|
||||
data = HEADER + "Error: " + ioe + FOOTER;
|
||||
}
|
||||
} else {
|
||||
data = HEADER + "No peer data available. The router is not running." + FOOTER;
|
||||
}
|
||||
try {
|
||||
wv.loadData(data, "text/html", "UTF-8");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
WebView wv = (WebView) findViewById(R.id.peers_webview);
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
|
||||
_wvClient.cancelAll();
|
||||
wv.stopLoading();
|
||||
if (wv.canGoBack()) {
|
||||
wv.goBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@ -50,14 +51,20 @@ public class RouterService extends Service {
|
||||
private Handler _handler;
|
||||
private Runnable _updater;
|
||||
|
||||
private static final String SHARED_PREFS = "net.i2p.android.router";
|
||||
private static final String LAST_STATE = "service.lastState";
|
||||
private static final String EXTRA_RESTART = "restart";
|
||||
private static final String MARKER = "************************************** ";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
State lastState = getSavedState();
|
||||
setState(State.INIT);
|
||||
System.err.println(this + " onCreate called" +
|
||||
" Saved state is: " + lastState +
|
||||
" Current state is: " + _state);
|
||||
|
||||
(new File(getFilesDir(), "wrapper.log")).delete();
|
||||
//(new File(getFilesDir(), "wrapper.log")).delete();
|
||||
_myDir = getFilesDir().getAbsolutePath();
|
||||
Init init = new Init(this);
|
||||
init.debugStuff();
|
||||
@ -67,27 +74,41 @@ public class RouterService extends Service {
|
||||
_binder = new RouterBinder(this);
|
||||
_handler = new Handler();
|
||||
_updater = new Updater();
|
||||
if (lastState == State.RUNNING) {
|
||||
Intent intent = new Intent(this, RouterService.class);
|
||||
intent.putExtra(EXTRA_RESTART, true);
|
||||
onStartCommand(intent, 12345, 67890);
|
||||
}
|
||||
}
|
||||
|
||||
/** NOT called by system if it restarts us after a crash */
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
System.err.println(this + " onStart called" +
|
||||
" Intent is: " + intent +
|
||||
" Flags is: " + flags +
|
||||
" ID is: " + startId +
|
||||
" Current state is: " + _state);
|
||||
boolean restart = intent != null && intent.getBooleanExtra(EXTRA_RESTART, false);
|
||||
if (restart)
|
||||
System.err.println(this + " RESTARTING");
|
||||
synchronized (_stateLock) {
|
||||
if (_state != State.INIT)
|
||||
//return START_STICKY;
|
||||
return START_NOT_STICKY;
|
||||
_receiver = new I2PReceiver(this);
|
||||
if (Util.isConnected(this)) {
|
||||
_statusBar.update("I2P is starting up");
|
||||
_state = State.STARTING;
|
||||
if (restart)
|
||||
_statusBar.update("I2P is restarting");
|
||||
else
|
||||
_statusBar.update("I2P is starting up");
|
||||
setState(State.STARTING);
|
||||
_starterThread = new Thread(new Starter());
|
||||
_starterThread.start();
|
||||
} else {
|
||||
_statusBar.update("I2P is waiting for a network connection");
|
||||
_state = State.WAITING;
|
||||
_starterThread = new Thread(new Waiter());
|
||||
_starterThread.start();
|
||||
setState(State.WAITING);
|
||||
_handler.postDelayed(new Waiter(), 10*1000);
|
||||
}
|
||||
}
|
||||
_handler.removeCallbacks(_updater);
|
||||
@ -108,7 +129,7 @@ public class RouterService extends Service {
|
||||
if (_state != State.WAITING)
|
||||
return;
|
||||
_statusBar.update("Network connected, I2P is starting up");
|
||||
_state = State.STARTING;
|
||||
setState(State.STARTING);
|
||||
_starterThread = new Thread(new Starter());
|
||||
_starterThread.start();
|
||||
}
|
||||
@ -130,7 +151,7 @@ public class RouterService extends Service {
|
||||
synchronized (_stateLock) {
|
||||
if (_state != State.STARTING)
|
||||
return;
|
||||
_state = State.RUNNING;
|
||||
setState(State.RUNNING);
|
||||
List contexts = RouterContext.listContexts();
|
||||
if ( (contexts == null) || (contexts.isEmpty()) )
|
||||
throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
|
||||
@ -193,7 +214,7 @@ public class RouterService extends Service {
|
||||
@Override
|
||||
public IBinder onBind(Intent intent)
|
||||
{
|
||||
System.err.println("onBind called" +
|
||||
System.err.println(this + "onBind called" +
|
||||
" Current state is: " + _state);
|
||||
return _binder;
|
||||
}
|
||||
@ -262,7 +283,7 @@ public class RouterService extends Service {
|
||||
Thread stopperThread = new Thread(new Stopper(State.MANUAL_QUITTING, State.MANUAL_QUITTED));
|
||||
stopperThread.start();
|
||||
} else if (_state == State.WAITING) {
|
||||
_state = State.MANUAL_QUITTING;
|
||||
setState(State.MANUAL_QUITTING);
|
||||
(new FinalShutdownHook()).run();
|
||||
}
|
||||
}
|
||||
@ -287,7 +308,8 @@ public class RouterService extends Service {
|
||||
}
|
||||
|
||||
public boolean canManualStart() {
|
||||
return _state == State.MANUAL_STOPPED || _state == State.STOPPED;
|
||||
// We can be in INIT if we restarted after crash but previous state was not RUNNING.
|
||||
return _state == State.INIT || _state == State.MANUAL_STOPPED || _state == State.STOPPED;
|
||||
}
|
||||
|
||||
public void manualStart() {
|
||||
@ -297,7 +319,7 @@ public class RouterService extends Service {
|
||||
if (!canManualStart())
|
||||
return;
|
||||
_statusBar.update("I2P is starting up");
|
||||
_state = State.STARTING;
|
||||
setState(State.STARTING);
|
||||
_starterThread = new Thread(new Starter());
|
||||
_starterThread.start();
|
||||
}
|
||||
@ -355,7 +377,7 @@ public class RouterService extends Service {
|
||||
public Stopper(State next, State stop) {
|
||||
nextState = next;
|
||||
stopState = stop;
|
||||
_state = next;
|
||||
setState(next);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
@ -368,7 +390,7 @@ public class RouterService extends Service {
|
||||
System.err.println("********** Router shutdown complete");
|
||||
synchronized (_stateLock) {
|
||||
if (_state == nextState)
|
||||
_state = stopState;
|
||||
setState(stopState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -401,7 +423,7 @@ public class RouterService extends Service {
|
||||
_starterThread.interrupt();
|
||||
if (_state == State.WAITING || _state == State.STARTING ||
|
||||
_state == State.RUNNING)
|
||||
_state = State.STOPPING;
|
||||
setState(State.STOPPING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -427,21 +449,44 @@ public class RouterService extends Service {
|
||||
if (_state == State.STARTING)
|
||||
_starterThread.interrupt();
|
||||
if (_state == State.MANUAL_STOPPING) {
|
||||
_state = State.MANUAL_STOPPED;
|
||||
setState(State.MANUAL_STOPPED);
|
||||
} else if (_state == State.NETWORK_STOPPING) {
|
||||
// start waiter handler
|
||||
_state = State.WAITING;
|
||||
setState(State.WAITING);
|
||||
_handler.postDelayed(new Waiter(), 10*1000);
|
||||
} else if (_state == State.STARTING || _state == State.RUNNING ||
|
||||
_state == State.STOPPING) {
|
||||
System.err.println(this + " died of unknown causes");
|
||||
_state = State.STOPPED;
|
||||
setState(State.STOPPED);
|
||||
stopSelf();
|
||||
} else if (_state == State.MANUAL_QUITTING) {
|
||||
_state = State.MANUAL_QUITTED;
|
||||
setState(State.MANUAL_QUITTED);
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private State getSavedState() {
|
||||
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS, 0);
|
||||
String stateString = prefs.getString(LAST_STATE, State.INIT.toString());
|
||||
for (State s : State.values()) {
|
||||
if (s.toString().equals(stateString))
|
||||
return s;
|
||||
}
|
||||
return State.INIT;
|
||||
}
|
||||
|
||||
private void setState(State s) {
|
||||
_state = s;
|
||||
saveState();
|
||||
}
|
||||
|
||||
/** @return success */
|
||||
private boolean saveState() {
|
||||
SharedPreferences prefs = getSharedPreferences(SHARED_PREFS, 0);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putString(LAST_STATE, _state.toString());
|
||||
return edit.commit();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public abstract class Util {
|
||||
String us = ctx.getPackageName();
|
||||
try {
|
||||
PackageInfo pi = pm.getPackageInfo(us, 0);
|
||||
System.err.println("VersionCode" + ": " + pi.versionCode);
|
||||
//System.err.println("VersionCode" + ": " + pi.versionCode);
|
||||
// http://doandroids.com/blogs/2010/6/10/android-classloader-dynamic-loading-of/
|
||||
//_apkPath = pm.getApplicationInfo(us, 0).sourceDir;
|
||||
//System.err.println("APK Path" + ": " + _apkPath);
|
||||
|
Reference in New Issue
Block a user