diff --git a/android/.gitignore b/android/.gitignore
index 90cd315e..d9fa5a57 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -5,11 +5,4 @@ ant.properties
local.properties
build.sh
bin
-log*
-.gradle
-android.iml
-build
-gradle
-gradlew
-gradlew.bat
-
+log*
\ No newline at end of file
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 1421b261..c147a808 100755
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -1,17 +1,12 @@
i2pd
+ i2pd started
+ i2pd service started
+ i2pd service stopped
Stop
Graceful Stop
Graceful stop is already in progress
Graceful stop is in progress
Already stopped
- i2pd initializing
- i2pd is starting
- i2pd: loaded JNI libraries
- i2pd started
- i2pd start failed
- i2pd: graceful shutdown in progress
- i2pd has stopped
- remaining
diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java
index 4f3e62f7..64568f83 100644
--- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java
+++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java
@@ -8,8 +8,8 @@ import android.util.Log;
public class DaemonSingleton {
private static final String TAG="i2pd";
private static final DaemonSingleton instance = new DaemonSingleton();
- public interface StateUpdateListener { void daemonStateUpdate(); }
- private final Set stateUpdateListeners = new HashSet<>();
+ public static interface StateUpdateListener { void daemonStateUpdate(); }
+ private final Set stateUpdateListeners = new HashSet();
public static DaemonSingleton getInstance() {
return instance;
@@ -18,72 +18,63 @@ public class DaemonSingleton {
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
- private synchronized void setState(State newState) {
- if(newState==null)throw new NullPointerException();
- State oldState = state;
- if(oldState==null)throw new NullPointerException();
- if(oldState.equals(newState))return;
- state=newState;
- fireStateUpdate1();
- }
public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){
- setState(State.gracefulShutdownInProgress);
+ state=State.gracefulShutdownInProgress;
+ fireStateUpdate();
I2PD_JNI.stopAcceptingTunnels();
}
}
- private volatile boolean startedOkay;
+ public void onNetworkStateChange(boolean isConnected) {
+ I2PD_JNI.onNetworkStateChanged(isConnected);
+ }
- public enum State {
- uninitialized(R.string.uninitialized),
- starting(R.string.starting),
- jniLibraryLoaded(R.string.jniLibraryLoaded),
- startedOkay(R.string.startedOkay),
- startFailed(R.string.startFailed),
- gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
- stopped(R.string.stopped);
+ private boolean startedOkay;
- State(int statusStringResourceId) {
- this.statusStringResourceId = statusStringResourceId;
- }
+ public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress,stopped};
- private final int statusStringResourceId;
-
- public int getStatusStringResourceId() {
- return statusStringResourceId;
- }
- };
-
- private volatile State state = State.uninitialized;
+ private State state = State.uninitialized;
public State getState() { return state; }
- {
- setState(State.starting);
+ 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();
- setState(State.jniLibraryLoaded);
+ synchronized (DaemonSingleton.this) {
+ state = State.jniLibraryLoaded;
+ fireStateUpdate();
+ }
} catch (Throwable tr) {
lastThrowable=tr;
- setState(State.startFailed);
+ synchronized (DaemonSingleton.this) {
+ state = State.startFailed;
+ fireStateUpdate();
+ }
return;
}
try {
synchronized (DaemonSingleton.this) {
daemonStartResult = I2PD_JNI.startDaemon();
if("ok".equals(daemonStartResult)){
- setState(State.startedOkay);
+ state=State.startedOkay;
setStartedOkay(true);
- }else setState(State.startFailed);
+ }else state=State.startFailed;
+ fireStateUpdate();
}
} catch (Throwable tr) {
lastThrowable=tr;
- setState(State.startFailed);
+ synchronized (DaemonSingleton.this) {
+ state = State.startFailed;
+ fireStateUpdate();
+ }
return;
}
}
@@ -93,7 +84,7 @@ public class DaemonSingleton {
private Throwable lastThrowable;
private String daemonStartResult="N/A";
- private void fireStateUpdate1() {
+ private synchronized void fireStateUpdate() {
Log.i(TAG, "daemon state change: "+state);
for(StateUpdateListener listener : stateUpdateListeners) {
try {
@@ -130,7 +121,10 @@ public class DaemonSingleton {
if(isStartedOkay()){
try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);}
setStartedOkay(false);
- setState(State.stopped);
+ synchronized (DaemonSingleton.this) {
+ state = State.stopped;
+ fireStateUpdate();
+ }
}
}
}
diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java
index 6116b982..74761b07 100644
--- a/android/src/org/purplei2p/i2pd/ForegroundService.java
+++ b/android/src/org/purplei2p/i2pd/ForegroundService.java
@@ -11,32 +11,11 @@ import android.util.Log;
import android.widget.Toast;
public class ForegroundService extends Service {
- private static final String TAG="FgService";
-
- private volatile boolean shown;
-
- private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
- new DaemonSingleton.StateUpdateListener() {
-
- @Override
- public void daemonStateUpdate() {
- try {
- synchronized (ForegroundService.this) {
- if (shown) cancelNotification();
- showNotification();
- }
- } catch (Throwable tr) {
- Log.e(TAG,"error ignored",tr);
- }
- }
- };
-
-
private NotificationManager notificationManager;
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
- private int NOTIFICATION = 1;
+ private int NOTIFICATION = R.string.i2pd_started;
/**
* Class for clients to access. Because we know this service always
@@ -53,35 +32,29 @@ public class ForegroundService extends Service {
public void onCreate() {
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- synchronized (this) {
- DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
- if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
- }
+ // 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();
+ 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);
+ daemon.start();
return START_STICKY;
}
@Override
public void onDestroy() {
- DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
- cancelNotification();
- }
-
- private synchronized void cancelNotification() {
// Cancel the persistent notification.
notificationManager.cancel(NOTIFICATION);
stopForeground(true);
// Tell the user we stopped.
-// Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
- shown=false;
+ Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
}
@Override
@@ -96,9 +69,9 @@ public class ForegroundService extends Service {
/**
* Show a notification while this service is running.
*/
- private synchronized void showNotification() {
+ private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
- CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
+ CharSequence text = getText(R.string.i2pd_started);
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
@@ -117,9 +90,8 @@ public class ForegroundService extends Service {
// Send the notification.
//mNM.notify(NOTIFICATION, notification);
startForeground(NOTIFICATION, notification);
- shown=true;
}
- private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
+ private final DaemonSingleton daemon = DaemonSingleton.getInstance();
}
diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java
index 99672eb7..36e992b3 100755
--- a/android/src/org/purplei2p/i2pd/I2PDActivity.java
+++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java
@@ -19,14 +19,13 @@ import android.widget.TextView;
import android.widget.Toast;
public class I2PDActivity extends Activity {
- private static final String TAG = "i2pdActvt";
- public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
+ private static final String TAG = "i2pd";
- private TextView textView;
+ private TextView textView;
- private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
+ private final DaemonSingleton daemon = DaemonSingleton.getInstance();
- private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
+ private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() {
@Override
@@ -43,11 +42,8 @@ public class I2PDActivity extends Activity {
return;
}
DaemonSingleton.State state = daemon.getState();
- textView.setText(
- String.valueOf(state)+
- (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+
- (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"")
- );
+ textView.setText(String.valueOf(state)+
+ (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():""));
} catch (Throwable tr) {
Log.e(TAG,"error ignored",tr);
}
@@ -55,18 +51,6 @@ public class I2PDActivity extends Activity {
});
}
};
- private static volatile long graceStartedMillis;
- private static final Object graceStartedMillis_LOCK=new Object();
-
- private static String formatGraceTimeRemaining() {
- long remainingSeconds;
- synchronized (graceStartedMillis_LOCK){
- remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D);
- }
- long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D);
- long remSec=remainingSeconds-remainingMinutes*60;
- return remainingMinutes+":"+(remSec/10)+remSec%10;
- }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -74,44 +58,35 @@ public class I2PDActivity extends Activity {
textView = new TextView(this);
setContentView(textView);
- daemon.addStateChangeListener(daemonStateUpdatedListener);
+ DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
daemonStateUpdatedListener.daemonStateUpdate();
//set the app be foreground
doBindService();
-
- final Timer gracefulQuitTimer = getGracefulQuitTimer();
- if(gracefulQuitTimer!=null){
- long gracefulStopAtMillis;
- synchronized (graceStartedMillis_LOCK) {
- gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
- }
- rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
- }
}
@Override
protected void onDestroy() {
super.onDestroy();
- textView = null;
- daemon.removeStateChangeListener(daemonStateUpdatedListener);
- //cancelGracefulStop();
- try{
- doUnbindService();
- }catch(Throwable tr){
- Log.e(TAG, "", tr);
- }
+ localDestroy();
}
- private static void cancelGracefulStop() {
- Timer gracefulQuitTimer = getGracefulQuitTimer();
- if(gracefulQuitTimer!=null) {
- gracefulQuitTimer.cancel();
- setGracefulQuitTimer(null);
- }
- }
+ private void localDestroy() {
+ textView = null;
+ DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
+ Timer gracefulQuitTimer = getGracefulQuitTimer();
+ if(gracefulQuitTimer!=null) {
+ gracefulQuitTimer.cancel();
+ setGracefulQuitTimer(null);
+ }
+// try{
+// doUnbindService();
+// }catch(Throwable tr){
+// Log.e(TAG, "", tr);
+// }
+ }
- private CharSequence throwableToString(Throwable tr) {
+ private CharSequence throwableToString(Throwable tr) {
StringWriter sw = new StringWriter(8192);
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
@@ -147,27 +122,24 @@ public class I2PDActivity extends Activity {
};
- private static volatile boolean mIsBound;
+ private boolean mIsBound;
- private void doBindService() {
- synchronized (I2PDActivity.class) {
- if (mIsBound) return;
- // Establish a connection with the service. We use an explicit
- // class name because we want a specific service implementation that
- // we know will be running in our own process (and thus won't be
- // supporting component replacement by other applications).
- bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE);
- mIsBound = true;
- }
+ private synchronized void doBindService() {
+ if(mIsBound)return;
+ // Establish a connection with the service. We use an explicit
+ // class name because we want a specific service implementation that
+ // we know will be running in our own process (and thus won't be
+ // supporting component replacement by other applications).
+ bindService(new Intent(this,
+ ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE);
+ mIsBound = true;
}
private void doUnbindService() {
- synchronized (I2PDActivity.class) {
- if (mIsBound) {
- // Detach our existing connection.
- unbindService(mConnection);
- mIsBound = false;
- }
+ if (mIsBound) {
+ // Detach our existing connection.
+ unbindService(mConnection);
+ mIsBound = false;
}
}
@@ -198,25 +170,16 @@ public class I2PDActivity extends Activity {
}
private void i2pdStop() {
- cancelGracefulStop();
- new Thread(new Runnable(){
-
- @Override
- public void run() {
- Log.d(TAG, "stopping");
- try{
- daemon.stopDaemon();
- }catch (Throwable tr) {
- Log.e(TAG, "", tr);
- }
- }
-
- },"stop").start();
+ try{
+ daemon.stopDaemon();
+ }catch (Throwable tr) {
+ Log.e(TAG, "", tr);
+ }
}
- private static volatile Timer gracefulQuitTimer;
-
- private void i2pdGracefulStop() {
+ private Timer gracefulQuitTimer;
+ private final Object gracefulQuitTimerLock = new Object();
+ private synchronized void i2pdGracefulStop() {
if(daemon.getState()==DaemonSingleton.State.stopped){
Toast.makeText(this, R.string.already_stopped,
Toast.LENGTH_SHORT).show();
@@ -237,12 +200,16 @@ public class I2PDActivity extends Activity {
Log.d(TAG, "grac stopping");
if(daemon.isStartedOkay()) {
daemon.stopAcceptingTunnels();
- long gracefulStopAtMillis;
- synchronized (graceStartedMillis_LOCK) {
- graceStartedMillis = System.currentTimeMillis();
- gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
- }
- rescheduleGraceStop(null,gracefulStopAtMillis);
+ Timer gracefulQuitTimer = new Timer(true);
+ setGracefulQuitTimer(gracefulQuitTimer);
+ gracefulQuitTimer.schedule(new TimerTask(){
+
+ @Override
+ public void run() {
+ i2pdStop();
+ }
+
+ }, 10*60*1000/*milliseconds*/);
}else{
i2pdStop();
}
@@ -251,35 +218,18 @@ public class I2PDActivity extends Activity {
}
}
- },"gracInit").start();
+ },"gracQuitInit").start();
}
- private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
- if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel();
- final Timer gracefulQuitTimer = new Timer(true);
- setGracefulQuitTimer(gracefulQuitTimer);
- gracefulQuitTimer.schedule(new TimerTask(){
-
- @Override
- public void run() {
- i2pdStop();
- }
-
- }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis()));
- final TimerTask tickerTask = new TimerTask() {
- @Override
- public void run() {
- daemonStateUpdatedListener.daemonStateUpdate();
- }
- };
- gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/);
- }
-
- private static Timer getGracefulQuitTimer() {
- return gracefulQuitTimer;
+ private Timer getGracefulQuitTimer() {
+ synchronized (gracefulQuitTimerLock) {
+ return gracefulQuitTimer;
+ }
}
- private static void setGracefulQuitTimer(Timer gracefulQuitTimer) {
- I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
+ private void setGracefulQuitTimer(Timer gracefulQuitTimer) {
+ synchronized (gracefulQuitTimerLock) {
+ this.gracefulQuitTimer = gracefulQuitTimer;
+ }
}
}