diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 229ff16c2f50c196f2469ec87da10805f1e70800..3b57d4b1a41551e46ceaaa041a247ae5c3f57eae 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -19,7 +19,7 @@ android:label="I2P Main Page" android:icon="@drawable/ic_launcher_itoopie" android.theme="@android:style/Theme.NoTitleBar" - android:launchMode="singleTask" > + android:launchMode="singleTop" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -43,7 +43,8 @@ </activity> <activity android:name=".activity.SettingsActivity" android:label="Settings" - android.theme="@android:style/Theme.NoTitleBar" > + android.theme="@android:style/Theme.NoTitleBar" + android:launchMode="singleTop" > </activity> </application> </manifest> diff --git a/build.xml b/build.xml index 52153ca7e41d40f28b49e1f98e9c222e96fdb461..8826ca601413a9e53e4a02c13b7a4a1c09610394 100644 --- a/build.xml +++ b/build.xml @@ -80,6 +80,8 @@ <target name="-pre-build" depends="findI2PSource, copy-i2p-resources, incrementBuild" > <!-- aapt messes up when resources are added or deleted, just build every time --> <delete dir="${gen.absolute.dir}/net" verbose="${verbose}" /> + <!-- screw it, do the classes too --> + <delete dir="${out.absolute.dir}/net" verbose="${verbose}" /> </target> <target name="-pre-compile" depends="buildrouter" /> diff --git a/res/layout/main.xml b/res/layout/main.xml index b16744faab4f048268e449ab1a9783ddc5f8f522..d1a21b8761334877fd8780d7c4710116c3fe8d1e 100644 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -80,6 +80,12 @@ android:layout_height="wrap_content" android:text="Stop router" /> + <Button + android:id="@+id/router_quit_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="QUIT router" + /> </LinearLayout> <TextView android:id="@+id/main_status_text" diff --git a/res/menu/menu1.xml b/res/menu/menu1.xml index 9ef1eb1af5a84052370d839cc1c5e341c51e4597..b7857aa382db4249e80dc28624850312ec13a796 100755 --- a/res/menu/menu1.xml +++ b/res/menu/menu1.xml @@ -1,17 +1,18 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:title="Preferences" - android:titleCondensed="Settings" - android:id="@+id/menu_settings" - android:icon="@android:drawable/ic_menu_preferences" > - </item> <item android:title="Start Router" android:id="@+id/menu_start" - android:titleCondensed="Start" android:icon="@drawable/ic_menu_play_clip" > </item> <item android:title="Stop Router" android:id="@+id/menu_stop" - android:titleCondensed="Stop" android:icon="@android:drawable/ic_menu_close_clear_cancel" > </item> + <item android:title="I2P Home" + android:id="@+id/menu_home" + android:icon="@drawable/ic_menu_home" > + </item> + <item android:title="Settings" + android:id="@+id/menu_settings" + android:icon="@android:drawable/ic_menu_preferences" > + </item> </menu> diff --git a/src/net/i2p/android/router/activity/I2PActivityBase.java b/src/net/i2p/android/router/activity/I2PActivityBase.java index 38e014cb983813c25aa44e1886e1c6d0a29d0b18..a10f39a1a0c633c1fa57219985bad6e0f463401b 100644 --- a/src/net/i2p/android/router/activity/I2PActivityBase.java +++ b/src/net/i2p/android/router/activity/I2PActivityBase.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; @@ -27,6 +28,10 @@ public abstract class I2PActivityBase extends Activity { protected boolean _isBound; protected ServiceConnection _connection; protected RouterService _routerService; + private SharedPreferences _sharedPrefs; + + private static final String SHARED_PREFS = "net.i2p.android.router"; + protected static final String PREF_AUTO_START = "autoStart"; /** Called when the activity is first created. */ @Override @@ -49,7 +54,15 @@ public abstract class I2PActivityBase extends Activity { { System.err.println(this + " onStart called"); super.onStart(); - startRouter(); + _sharedPrefs = getSharedPreferences(SHARED_PREFS, 0); + if (_sharedPrefs.getBoolean(PREF_AUTO_START, true)) + startRouter(); + } + + protected void setAutoStart(boolean yes) { + SharedPreferences.Editor edit = _sharedPrefs.edit(); + edit.putBoolean(PREF_AUTO_START, yes); + edit.commit(); } protected boolean startRouter() { @@ -112,6 +125,22 @@ public abstract class I2PActivityBase extends Activity { @Override public boolean onPrepareOptionsMenu(Menu menu) { // add/hide items here + RouterService svc = _routerService; + boolean showStart = (svc == null) || (svc != null && _isBound && svc.canManualStart()); + MenuItem start = menu.findItem(R.id.menu_start); + start.setVisible(showStart); + start.setEnabled(showStart); + + boolean showStop = svc != null && _isBound && svc.canManualStop(); + MenuItem stop = menu.findItem(R.id.menu_stop); + stop.setVisible(showStop); + stop.setEnabled(showStop); + + boolean showHome = ! (this instanceof MainActivity); + MenuItem home = menu.findItem(R.id.menu_home); + home.setVisible(showHome); + home.setEnabled(showHome); + return super.onPrepareOptionsMenu(menu); } @@ -120,8 +149,14 @@ public abstract class I2PActivityBase extends Activity { switch (item.getItemId()) { case R.id.menu_settings: Intent intent = new Intent(I2PActivityBase.this, SettingsActivity.class); - startActivityForResult(intent, 0); + startActivity(intent); + return true; + + case R.id.menu_home: + Intent i2 = new Intent(I2PActivityBase.this, MainActivity.class); + startActivity(i2); return true; + case R.id.menu_start: case R.id.menu_stop: default: @@ -159,6 +194,8 @@ public abstract class I2PActivityBase extends Activity { public void onServiceDisconnected(ComponentName name) { System.err.println(this + " disconnected from router service!!!!!!!"); + // save memory + _routerService = null; _isBound = false; } } @@ -166,9 +203,10 @@ public abstract class I2PActivityBase extends Activity { ////// Router stuff protected RouterContext getRouterContext() { - if (_routerService == null || !_isBound) + RouterService svc = _routerService; + if (svc == null || !_isBound) return null; - return _routerService.getRouterContext(); + return svc.getRouterContext(); } protected Router getRouter() { diff --git a/src/net/i2p/android/router/activity/I2PWebViewClient.java b/src/net/i2p/android/router/activity/I2PWebViewClient.java index 69d613555c3f627f71dea4d264eacb66c6019f5c..c0ce67936c26eafabad6d02d9f32e5070c4893a6 100644 --- a/src/net/i2p/android/router/activity/I2PWebViewClient.java +++ b/src/net/i2p/android/router/activity/I2PWebViewClient.java @@ -76,6 +76,16 @@ class I2PWebViewClient extends WebViewClient { } } +/****** + API 11 :( + + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + + } + +******/ + void cancelAll() { BGLoad task = _lastTask; if (task != null) { diff --git a/src/net/i2p/android/router/activity/LicenseActivity.java b/src/net/i2p/android/router/activity/LicenseActivity.java index 6d70a2a85260e44d23512ce86ac3d0be5d986224..ac2dba2f78dcdcdbd0bcaf476cf77e266add85fe 100644 --- a/src/net/i2p/android/router/activity/LicenseActivity.java +++ b/src/net/i2p/android/router/activity/LicenseActivity.java @@ -42,7 +42,7 @@ public class LicenseActivity extends I2PActivityBase { public void onClick(View view) { Intent intent = new Intent(view.getContext(), TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, resource); - startActivityForResult(intent, 0); + startActivity(intent); } } } diff --git a/src/net/i2p/android/router/activity/MainActivity.java b/src/net/i2p/android/router/activity/MainActivity.java index 3b4f30a2fa83903c830dfad9636aecd5615c1d5b..4a689ef846601920a5a91427389d8c78c109474a 100644 --- a/src/net/i2p/android/router/activity/MainActivity.java +++ b/src/net/i2p/android/router/activity/MainActivity.java @@ -14,6 +14,7 @@ import android.widget.TextView; import java.text.DecimalFormat; import net.i2p.android.router.R; +import net.i2p.android.router.service.RouterService; import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; @@ -39,7 +40,7 @@ public class MainActivity extends I2PActivityBase { news.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent intent = new Intent(view.getContext(), NewsActivity.class); - startActivityForResult(intent, 0); + startActivity(intent); } }); @@ -48,7 +49,7 @@ public class MainActivity extends I2PActivityBase { public void onClick(View view) { Intent intent = new Intent(view.getContext(), TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); - startActivityForResult(intent, 0); + startActivity(intent); } }); @@ -58,7 +59,7 @@ public class MainActivity extends I2PActivityBase { Intent intent = new Intent(view.getContext(), LicenseActivity.class); //Intent intent = new Intent(view.getContext(), TextResourceActivity.class); //intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.licenses_txt); - startActivityForResult(intent, 0); + startActivity(intent); } }); @@ -68,7 +69,7 @@ public class MainActivity extends I2PActivityBase { Intent intent = new Intent(view.getContext(), WebActivity.class); //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/").build()); intent.setData(Uri.parse("http://www.i2p2.de/")); - startActivityForResult(intent, 0); + startActivity(intent); } }); @@ -78,7 +79,7 @@ public class MainActivity extends I2PActivityBase { Intent intent = new Intent(view.getContext(), WebActivity.class); //intent.setData((new Uri.Builder()).scheme("http").authority("www.i2p2.de").path("/faq").build()); intent.setData(Uri.parse("http://www.i2p2.de/faq")); - startActivityForResult(intent, 0); + startActivity(intent); } }); @@ -87,26 +88,44 @@ public class MainActivity extends I2PActivityBase { public void onClick(View view) { Intent intent = new Intent(view.getContext(), WebActivity.class); // default is to display the welcome_html resource - startActivityForResult(intent, 0); + startActivity(intent); } }); Button start = (Button) findViewById(R.id.router_start_button); start.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - if (_routerService != null && _isBound) { - _routerService.manualStart(); - updateVisibility(); + RouterService svc = _routerService; + if (svc != null && _isBound) { + setAutoStart(true); + svc.manualStart(); + } else { + startRouter(); } + updateVisibility(); } }); Button stop = (Button) findViewById(R.id.router_stop_button); stop.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - if (_routerService != null && _isBound) { - _routerService.manualStop(); - updateVisibility(); + RouterService svc = _routerService; + if (svc != null && _isBound) { + setAutoStart(false); + svc.manualStop(); + updateVisibility(); + } + } + }); + + Button quit = (Button) findViewById(R.id.router_quit_button); + quit.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + RouterService svc = _routerService; + if (svc != null && _isBound) { + setAutoStart(false); + svc.manualQuit(); + updateVisibility(); } } }); @@ -122,7 +141,6 @@ public class MainActivity extends I2PActivityBase { _updater = new Updater(); } - @Override public void onStart() { @@ -176,13 +194,17 @@ public class MainActivity extends I2PActivityBase { } private void updateVisibility() { - boolean showStart = _routerService != null && _isBound && _routerService.canManualStart(); + RouterService svc = _routerService; + boolean showStart = (svc == null) || (svc != null && _isBound && svc.canManualStart()); Button start = (Button) findViewById(R.id.router_start_button); start.setVisibility(showStart ? View.VISIBLE : View.INVISIBLE); - boolean showStop = _routerService != null && _isBound && _routerService.canManualStop(); + boolean showStop = svc != null && _isBound && svc.canManualStop(); Button stop = (Button) findViewById(R.id.router_stop_button); stop.setVisibility(showStop ? View.VISIBLE : View.INVISIBLE); + + Button quit = (Button) findViewById(R.id.router_quit_button); + quit.setVisibility(showStop ? View.VISIBLE : View.INVISIBLE); } private void updateStatus() { @@ -264,7 +286,7 @@ public class MainActivity extends I2PActivityBase { MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); - startActivityForResult(intent, 0); + startActivity(intent); } }) .setNegativeButton("Licenses", new DialogInterface.OnClickListener() { @@ -274,7 +296,7 @@ public class MainActivity extends I2PActivityBase { dialog.cancel(); MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, LicenseActivity.class); - startActivityForResult(intent, 0); + startActivity(intent); } }); rv = b.create(); @@ -301,7 +323,7 @@ public class MainActivity extends I2PActivityBase { MainActivity.this.removeDialog(id); Intent intent = new Intent(MainActivity.this, TextResourceActivity.class); intent.putExtra(TextResourceActivity.TEXT_RESOURCE_ID, R.raw.releasenotes_txt); - startActivityForResult(intent, 0); + startActivity(intent); } }); diff --git a/src/net/i2p/android/router/receiver/I2PReceiver.java b/src/net/i2p/android/router/receiver/I2PReceiver.java index 6a9c2186163f0d91a5b074a87182c24594bd3986..6ec54001fec55a473be1767d19904cc0b9eea1b8 100644 --- a/src/net/i2p/android/router/receiver/I2PReceiver.java +++ b/src/net/i2p/android/router/receiver/I2PReceiver.java @@ -63,9 +63,10 @@ public class I2PReceiver extends BroadcastReceiver { if (_wasConnected && !connected) { // notify + 2 timer ticks if (++_unconnectedCount >= 3) { - if (_isBound) { + RouterService svc = _routerService; + if (_isBound && svc != null) { System.err.println("********* Network down, already bound"); - _routerService.networkStop(); + svc.networkStop(); } else { System.err.println("********* Network down, binding to router"); // connection will call networkStop() @@ -131,6 +132,7 @@ public class I2PReceiver extends BroadcastReceiver { private class RouterConnection implements ServiceConnection { + /** Stops the router when connected */ public void onServiceConnected(ComponentName name, IBinder service) { RouterBinder binder = (RouterBinder) service; _routerService = binder.getService(); @@ -145,6 +147,7 @@ public class I2PReceiver extends BroadcastReceiver { public void onServiceDisconnected(ComponentName name) { _isBound = false; + _routerService = null; System.err.println("********* Receiver unbinding from router"); } } diff --git a/src/net/i2p/android/router/service/RouterService.java b/src/net/i2p/android/router/service/RouterService.java index e5c3175e6702996c0c582a2d357416f17ace292c..16daf3a6a95525baf5de80b17c7a0d1e30e8195a 100644 --- a/src/net/i2p/android/router/service/RouterService.java +++ b/src/net/i2p/android/router/service/RouterService.java @@ -26,9 +26,16 @@ import net.i2p.util.NativeBigInteger; * Runs the router */ public class RouterService extends Service { - private enum State {INIT, WAITING, STARTING, RUNNING, STOPPING, STOPPED, + private enum State {INIT, WAITING, STARTING, RUNNING, + // unplanned (router stopped itself), next: killSelf() + STOPPING, STOPPED, + // button, don't kill service when stopped, stay in MANUAL_STOPPED MANUAL_STOPPING, MANUAL_STOPPED, - NETWORK_STOPPING, NETWORK_STOPPED, RESTARTING} + // button, DO kill service when stopped, next: killSelf() + MANUAL_QUITTING, MANUAL_QUITTED, + // Stopped by listener (no network), next: WAITING (spin waiting for network) + NETWORK_STOPPING, NETWORK_STOPPED + } private RouterContext _context; private String _myDir; @@ -210,6 +217,7 @@ public class RouterService extends Service { if (_state != State.RUNNING && _state != State.STOPPING && _state != State.MANUAL_STOPPING && + _state != State.MANUAL_QUITTING && _state != State.NETWORK_STOPPING) return null; return rv; @@ -220,7 +228,7 @@ public class RouterService extends Service { } /** - * Stop and don't restart + * Stop and don't restart the router, but keep the service */ public void manualStop() { System.err.println("manualStop called" + @@ -238,6 +246,25 @@ public class RouterService extends Service { } } + /** + * Stop the router and kill the service + */ + public void manualQuit() { + System.err.println("manualQuit called" + + " Current state is: " + _state); + synchronized (_stateLock) { + if (!canManualStop()) + return; + if (_state == State.WAITING || _state == State.STARTING) + _starterThread.interrupt(); + if (_state == State.STARTING || _state == State.RUNNING) { + _statusBar.update("Quitting I2P"); + Thread stopperThread = new Thread(new Stopper(State.MANUAL_QUITTING, State.MANUAL_QUITTED)); + stopperThread.start(); + } + } + } + /** * Stop and then spin waiting for a network connection, then restart */ @@ -275,6 +302,11 @@ public class RouterService extends Service { // ******** end methods accessed from Activities and Receivers ************ + /** + * Turn off the status bar. + * Unregister the receiver. + * If we were running, fire up the Stopper thread. + */ @Override public void onDestroy() { System.err.println("onDestroy called" + @@ -306,6 +338,12 @@ public class RouterService extends Service { } } + /** + * Transition to the next state. + * If we still have a context, shut down the router. + * Turn off the status bar. + * Then transition to the stop state. + */ private class Stopper implements Runnable { private final State nextState; private final State stopState; @@ -332,6 +370,11 @@ public class RouterService extends Service { } } + /** + * First (early) hook. + * Update the status bar. + * Unregister the receiver. + */ private class ShutdownHook implements Runnable { public void run() { System.err.println(this + " shutdown hook" + @@ -360,12 +403,20 @@ public class RouterService extends Service { } } + /** + * Second (late) hook. + * Turn off the status bar. + * Null out the context. + * If we were stopped manually, do nothing. + * If we were stopped because of no network, start the waiter thread. + * If it stopped of unknown causes or from manualQuit(), kill the Service. + */ private class FinalShutdownHook implements Runnable { public void run() { System.err.println(this + " final shutdown hook" + " Current state is: " + _state); _statusBar.off(RouterService.this); - I2PReceiver rcvr = _receiver; + //I2PReceiver rcvr = _receiver; synchronized (_stateLock) { // null out to release the memory @@ -381,8 +432,12 @@ public class RouterService extends Service { _starterThread.start(); } else if (_state == State.STARTING || _state == State.RUNNING || _state == State.STOPPING) { + System.err.println(this + " died of unknown causes"); _state = State.STOPPED; stopSelf(); + } else if (_state == State.MANUAL_QUITTING) { + _state = State.MANUAL_QUITTED; + stopSelf(); } } }