From 71546367cf7e1a75d464a0247e7c00ada2449569 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 7 Feb 2018 14:07:26 -0500 Subject: [PATCH] Revert "reworked the app, fixed #1094, fixed grace stop" --- android/.gitignore | 9 +- android/res/values/strings.xml | 11 +- .../org/purplei2p/i2pd/DaemonSingleton.java | 74 ++++---- .../org/purplei2p/i2pd/ForegroundService.java | 48 +---- .../src/org/purplei2p/i2pd/I2PDActivity.java | 178 +++++++----------- 5 files changed, 112 insertions(+), 208 deletions(-) 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 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); - - State(int statusStringResourceId) { - this.statusStringResourceId = statusStringResourceId; - } + public void onNetworkStateChange(boolean isConnected) { + I2PD_JNI.onNetworkStateChanged(isConnected); + } - private final int statusStringResourceId; + private boolean startedOkay; - public int getStatusStringResourceId() { - return statusStringResourceId; - } - }; + public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress,stopped}; - 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(); - } - - 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*/); + },"gracQuitInit").start(); } - 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; + } } }