diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index 8c78e88b..0b8bef38 100755 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -2,6 +2,8 @@ i2pd i2pd started + i2pd service started + i2pd service stopped Quit Graceful Quit Graceful quit is already in progress diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index 5e0ac4d0..e1ebc269 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -8,20 +8,20 @@ import android.util.Log; public class DaemonSingleton { private static final String TAG="i2pd"; private static final DaemonSingleton instance = new DaemonSingleton(); - public static interface StateChangeListener { void daemonStateChanged(); } - private final Set stateChangeListeners = new HashSet(); + public static interface StateUpdateListener { void daemonStateUpdate(); } + private final Set stateUpdateListeners = new HashSet(); public static DaemonSingleton getInstance() { return instance; } - public synchronized void addStateChangeListener(StateChangeListener listener) { stateChangeListeners.add(listener); } - public synchronized void removeStateChangeListener(StateChangeListener listener) { stateChangeListeners.remove(listener); } + public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } + public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } public synchronized void stopAcceptingTunnels() { if(isStartedOkay()){ state=State.gracefulShutdownInProgress; - fireStateChange(); + fireStateUpdate(); I2PD_JNI.stopAcceptingTunnels(); } } @@ -32,61 +32,63 @@ public class DaemonSingleton { private boolean startedOkay; - public static enum State {starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; + public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; - private State state = State.starting; + private State state = State.uninitialized; public State getState() { return state; } - { - synchronized(this){ - fireStateChange(); - new Thread(new Runnable(){ - - @Override - public void run() { - try { - I2PD_JNI.loadLibraries(); - synchronized (DaemonSingleton.this) { - state = State.jniLibraryLoaded; - fireStateChange(); - } - } catch (Throwable tr) { - lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateChange(); - } - return; + public synchronized void start() { + if(state != State.uninitialized)return; + state = State.starting; + fireStateUpdate(); + new Thread(new Runnable(){ + + @Override + public void run() { + try { + I2PD_JNI.loadLibraries(); + synchronized (DaemonSingleton.this) { + state = State.jniLibraryLoaded; + fireStateUpdate(); } - try { - synchronized (DaemonSingleton.this) { - daemonStartResult = I2PD_JNI.startDaemon(); - if("ok".equals(daemonStartResult)){state=State.startedOkay;setStartedOkay(true);} - else state=State.startFailed; - fireStateChange(); - } - } catch (Throwable tr) { - lastThrowable=tr; - synchronized (DaemonSingleton.this) { - state = State.startFailed; - fireStateChange(); - } - return; - } + } catch (Throwable tr) { + lastThrowable=tr; + synchronized (DaemonSingleton.this) { + state = State.startFailed; + fireStateUpdate(); + } + return; } - - }, "i2pdDaemonStart").start(); - } + try { + synchronized (DaemonSingleton.this) { + daemonStartResult = I2PD_JNI.startDaemon(); + if("ok".equals(daemonStartResult)){ + state=State.startedOkay; + setStartedOkay(true); + }else state=State.startFailed; + fireStateUpdate(); + } + } catch (Throwable tr) { + lastThrowable=tr; + synchronized (DaemonSingleton.this) { + state = State.startFailed; + fireStateUpdate(); + } + return; + } + } + + }, "i2pdDaemonStart").start(); } private Throwable lastThrowable; private String daemonStartResult="N/A"; - private synchronized void fireStateChange() { + private synchronized void fireStateUpdate() { Log.i(TAG, "daemon state change: "+state); - for(StateChangeListener listener : stateChangeListeners) { + for(StateUpdateListener listener : stateUpdateListeners) { try { - listener.daemonStateChanged(); + listener.daemonStateUpdate(); } catch (Throwable tr) { Log.e(TAG, "exception in listener ignored", tr); } diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index 16155651..d25d0a88 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -1,15 +1,17 @@ package org.purplei2p.i2pd; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; +import android.widget.Toast; public class ForegroundService extends Service { -// private NotificationManager mNM; + private NotificationManager notificationManager; // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. @@ -28,26 +30,31 @@ public class ForegroundService extends Service { @Override public void onCreate() { -// mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. We put an icon in the status bar. showNotification(); + daemon.start(); + // Tell the user we started. + Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ForegroundService", "Received start id " + startId + ": " + intent); - return START_NOT_STICKY; + daemon.start(); + return START_STICKY; } @Override public void onDestroy() { // Cancel the persistent notification. - //mNM.cancel(NOTIFICATION); + notificationManager.cancel(NOTIFICATION); + stopForeground(true); // Tell the user we stopped. - //Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); } @Override @@ -84,4 +91,7 @@ public class ForegroundService extends Service { //mNM.notify(NOTIFICATION, notification); startForeground(NOTIFICATION, notification); } + + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); } + diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java index 0397cf03..86b877ac 100755 --- a/android/src/org/purplei2p/i2pd/I2PD.java +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -22,12 +22,16 @@ import android.widget.Toast; public class I2PD extends Activity { private static final String TAG = "i2pd"; - private DaemonSingleton daemon = DaemonSingleton.getInstance(); - private DaemonSingleton.StateChangeListener daemonStateChangeListener = - new DaemonSingleton.StateChangeListener() { + + private TextView textView; + + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); + + private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = + new DaemonSingleton.StateUpdateListener() { @Override - public void daemonStateChanged() { + public void daemonStateUpdate() { runOnUiThread(new Runnable(){ @Override @@ -50,19 +54,17 @@ public class I2PD extends Activity { } }; - private TextView textView; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //set the app be foreground (do not unload when RAM needed) - doBindService(); - textView = new TextView(this); setContentView(textView); - daemonStateChangeListener.daemonStateChanged(); - daemon.addStateChangeListener(daemonStateChangeListener); + DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); + daemonStateUpdatedListener.daemonStateUpdate(); + + //set the app be foreground + doBindService(); } @Override @@ -73,7 +75,7 @@ public class I2PD extends Activity { private void localDestroy() { textView = null; - daemon.removeStateChangeListener(daemonStateChangeListener); + DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener); Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null) { gracefulQuitTimer.cancel();