mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	android: more logical daemon state changes
This commit is contained in:
		
							parent
							
								
									d9b87e877d
								
							
						
					
					
						commit
						db3e48a81a
					
				
					 3 changed files with 104 additions and 101 deletions
				
			
		| 
						 | 
				
			
			@ -12,7 +12,6 @@ import java.util.HashSet;
 | 
			
		|||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import android.annotation.TargetApi;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.res.AssetManager;
 | 
			
		||||
import android.net.ConnectivityManager;
 | 
			
		||||
import android.net.Network;
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +31,7 @@ public class DaemonWrapper {
 | 
			
		|||
	private boolean assetsCopied;
 | 
			
		||||
 | 
			
		||||
	public interface StateUpdateListener {
 | 
			
		||||
		void daemonStateUpdate();
 | 
			
		||||
		void daemonStateUpdate(State oldValue, State newValue);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +57,7 @@ public class DaemonWrapper {
 | 
			
		|||
			return;
 | 
			
		||||
 | 
			
		||||
		state = newState;
 | 
			
		||||
		fireStateUpdate1();
 | 
			
		||||
		fireStateUpdate1(oldState, newState);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public synchronized void stopAcceptingTunnels() {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,12 +80,10 @@ public class DaemonWrapper {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public synchronized int GetTransitTunnelsCount() {
 | 
			
		||||
	public int getTransitTunnelsCount() {
 | 
			
		||||
		return I2PD_JNI.GetTransitTunnelsCount();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private volatile boolean startedOkay;
 | 
			
		||||
 | 
			
		||||
	public enum State {
 | 
			
		||||
		uninitialized(R.string.uninitialized),
 | 
			
		||||
		starting(R.string.starting),
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +102,11 @@ public class DaemonWrapper {
 | 
			
		|||
		public int getStatusStringResourceId() {
 | 
			
		||||
			return statusStringResourceId;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
		public boolean isStartedOkay() {
 | 
			
		||||
			return equals(State.startedOkay) || equals(State.gracefulShutdownInProgress);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private volatile State state = State.uninitialized;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +135,6 @@ public class DaemonWrapper {
 | 
			
		|||
					daemonStartResult = I2PD_JNI.startDaemon();
 | 
			
		||||
					if ("ok".equals(daemonStartResult)) {
 | 
			
		||||
						setState(State.startedOkay);
 | 
			
		||||
						setStartedOkay(true);
 | 
			
		||||
					} else
 | 
			
		||||
						setState(State.startFailed);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -148,11 +148,11 @@ public class DaemonWrapper {
 | 
			
		|||
	private Throwable lastThrowable;
 | 
			
		||||
	private String daemonStartResult = "N/A";
 | 
			
		||||
 | 
			
		||||
	private void fireStateUpdate1() {
 | 
			
		||||
	private void fireStateUpdate1(State oldValue, State newValue) {
 | 
			
		||||
		Log.i(TAG, "daemon state change: " + state);
 | 
			
		||||
		for (StateUpdateListener listener : stateUpdateListeners) {
 | 
			
		||||
			try {
 | 
			
		||||
				listener.daemonStateUpdate();
 | 
			
		||||
				listener.daemonStateUpdate(oldValue, newValue);
 | 
			
		||||
			} catch (Throwable tr) {
 | 
			
		||||
				Log.e(TAG, "exception in listener ignored", tr);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -167,18 +167,8 @@ public class DaemonWrapper {
 | 
			
		|||
		return daemonStartResult;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private final Object startedOkayLock = new Object();
 | 
			
		||||
 | 
			
		||||
	public boolean isStartedOkay() {
 | 
			
		||||
		synchronized (startedOkayLock) {
 | 
			
		||||
			return startedOkay;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setStartedOkay(boolean startedOkay) {
 | 
			
		||||
		synchronized (startedOkayLock) {
 | 
			
		||||
			this.startedOkay = startedOkay;
 | 
			
		||||
		}
 | 
			
		||||
		return getState().isStartedOkay();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public synchronized void stopDaemon() {
 | 
			
		||||
| 
						 | 
				
			
			@ -189,7 +179,6 @@ public class DaemonWrapper {
 | 
			
		|||
				Log.e(TAG, "", tr);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			setStartedOkay(false);
 | 
			
		||||
			setState(State.stopped);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +186,7 @@ public class DaemonWrapper {
 | 
			
		|||
	private void processAssets() {
 | 
			
		||||
		if (!assetsCopied) {
 | 
			
		||||
			try {
 | 
			
		||||
				assetsCopied = true; // prevent from running on every state update
 | 
			
		||||
				assetsCopied = true;
 | 
			
		||||
 | 
			
		||||
				File holderFile = new File(i2pdpath, "assets.ready");
 | 
			
		||||
				String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
 | 
			
		||||
| 
						 | 
				
			
			@ -283,12 +272,10 @@ public class DaemonWrapper {
 | 
			
		|||
	 * Path to asset, relative to app's assets directory.
 | 
			
		||||
	 */
 | 
			
		||||
	private void copyAsset(String path) {
 | 
			
		||||
		AssetManager manager = assetManager;
 | 
			
		||||
 | 
			
		||||
		// If we have a directory, we make it and recurse. If a file, we copy its
 | 
			
		||||
		// contents.
 | 
			
		||||
		try {
 | 
			
		||||
			String[] contents = manager.list(path);
 | 
			
		||||
			String[] contents = assetManager.list(path);
 | 
			
		||||
 | 
			
		||||
			// The documentation suggests that list throws an IOException, but doesn't
 | 
			
		||||
			// say under what conditions. It'd be nice if it did so when the path was
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +342,7 @@ public class DaemonWrapper {
 | 
			
		|||
			Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void registerNetworkCallback(){
 | 
			
		||||
	private void registerNetworkCallback(){
 | 
			
		||||
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) registerNetworkCallback0();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,22 +23,28 @@ public class ForegroundService extends Service {
 | 
			
		|||
 | 
			
		||||
	private static volatile DaemonWrapper daemon;
 | 
			
		||||
 | 
			
		||||
	private static final Object initDeinitLock = new Object();
 | 
			
		||||
 | 
			
		||||
	private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener =
 | 
			
		||||
			new DaemonWrapper.StateUpdateListener() {
 | 
			
		||||
 | 
			
		||||
				@Override
 | 
			
		||||
				public void daemonStateUpdate() {
 | 
			
		||||
					try {
 | 
			
		||||
						synchronized (ForegroundService.this) {
 | 
			
		||||
							if (shown) cancelNotification();
 | 
			
		||||
							showNotification();
 | 
			
		||||
						}
 | 
			
		||||
					} catch (Throwable tr) {
 | 
			
		||||
						Log.e(TAG,"error ignored",tr);
 | 
			
		||||
					}
 | 
			
		||||
				public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) {
 | 
			
		||||
					updateNotificationText();
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
	private void updateNotificationText() {
 | 
			
		||||
		try {
 | 
			
		||||
			synchronized (initDeinitLock) {
 | 
			
		||||
				if (shown) cancelNotification();
 | 
			
		||||
				showNotification();
 | 
			
		||||
			}
 | 
			
		||||
		} catch (Throwable tr) {
 | 
			
		||||
			Log.e(TAG,"error ignored",tr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private NotificationManager notificationManager;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +69,9 @@ public class ForegroundService extends Service {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	private static void initCheck() {
 | 
			
		||||
		if(instance!=null && daemon!=null) instance.setListener();
 | 
			
		||||
		synchronized (initDeinitLock) {
 | 
			
		||||
			if (instance != null && daemon != null) instance.setListener();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +83,7 @@ public class ForegroundService extends Service {
 | 
			
		|||
 | 
			
		||||
	private void setListener() {
 | 
			
		||||
		daemon.addStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
		if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
		updateNotificationText();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -96,18 +104,23 @@ public class ForegroundService extends Service {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	private static void deinitCheck() {
 | 
			
		||||
		if(daemon!=null && instance!=null)daemon.removeStateChangeListener(instance.daemonStateUpdatedListener);
 | 
			
		||||
		synchronized (initDeinitLock) {
 | 
			
		||||
			if (daemon != null && instance != null)
 | 
			
		||||
				daemon.removeStateChangeListener(instance.daemonStateUpdatedListener);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private synchronized void cancelNotification() {
 | 
			
		||||
		// Cancel the persistent notification.
 | 
			
		||||
		notificationManager.cancel(NOTIFICATION);
 | 
			
		||||
	private void cancelNotification() {
 | 
			
		||||
		synchronized (initDeinitLock) {
 | 
			
		||||
			// Cancel the persistent notification.
 | 
			
		||||
			notificationManager.cancel(NOTIFICATION);
 | 
			
		||||
 | 
			
		||||
		stopForeground(true);
 | 
			
		||||
			stopForeground(true);
 | 
			
		||||
 | 
			
		||||
		// Tell the user we stopped.
 | 
			
		||||
		//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
 | 
			
		||||
		shown=false;
 | 
			
		||||
			// Tell the user we stopped.
 | 
			
		||||
			//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
 | 
			
		||||
			shown = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -122,39 +135,41 @@ public class ForegroundService extends Service {
 | 
			
		|||
	/**
 | 
			
		||||
	 * Show a notification while this service is running.
 | 
			
		||||
	 */
 | 
			
		||||
	private synchronized void showNotification() {
 | 
			
		||||
		if(daemon!=null) {
 | 
			
		||||
			// In this sample, we'll use the same text for the ticker and the expanded notification
 | 
			
		||||
			CharSequence text = getText(daemon.getState().getStatusStringResourceId());
 | 
			
		||||
	private void showNotification() {
 | 
			
		||||
		synchronized (initDeinitLock) {
 | 
			
		||||
			if (daemon != null) {
 | 
			
		||||
				// In this sample, we'll use the same text for the ticker and the expanded notification
 | 
			
		||||
				CharSequence text = getText(daemon.getState().getStatusStringResourceId());
 | 
			
		||||
 | 
			
		||||
			// The PendingIntent to launch our activity if the user selects this notification
 | 
			
		||||
			PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
 | 
			
		||||
					new Intent(this, I2PDActivity.class), 0);
 | 
			
		||||
				// The PendingIntent to launch our activity if the user selects this notification
 | 
			
		||||
				PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
 | 
			
		||||
						new Intent(this, I2PDActivity.class), 0);
 | 
			
		||||
 | 
			
		||||
			// If earlier version channel ID is not used
 | 
			
		||||
			// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
 | 
			
		||||
			String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
 | 
			
		||||
				// If earlier version channel ID is not used
 | 
			
		||||
				// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
 | 
			
		||||
				String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
 | 
			
		||||
 | 
			
		||||
			// Set the info for the views that show in the notification panel.
 | 
			
		||||
			NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
 | 
			
		||||
					.setOngoing(true)
 | 
			
		||||
					.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
 | 
			
		||||
			if (Build.VERSION.SDK_INT >= 16)
 | 
			
		||||
				builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
 | 
			
		||||
			if (Build.VERSION.SDK_INT >= 21)
 | 
			
		||||
				builder = builder.setCategory(Notification.CATEGORY_SERVICE);
 | 
			
		||||
			Notification notification = builder
 | 
			
		||||
					.setTicker(text) // the status text
 | 
			
		||||
					.setWhen(System.currentTimeMillis()) // the time stamp
 | 
			
		||||
					.setContentTitle(getText(R.string.app_name)) // the label of the entry
 | 
			
		||||
					.setContentText(text) // the contents of the entry
 | 
			
		||||
					.setContentIntent(contentIntent) // The intent to send when the entry is clicked
 | 
			
		||||
					.build();
 | 
			
		||||
				// Set the info for the views that show in the notification panel.
 | 
			
		||||
				NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
 | 
			
		||||
						.setOngoing(true)
 | 
			
		||||
						.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
 | 
			
		||||
				if (Build.VERSION.SDK_INT >= 16)
 | 
			
		||||
					builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
 | 
			
		||||
				if (Build.VERSION.SDK_INT >= 21)
 | 
			
		||||
					builder = builder.setCategory(Notification.CATEGORY_SERVICE);
 | 
			
		||||
				Notification notification = builder
 | 
			
		||||
						.setTicker(text) // the status text
 | 
			
		||||
						.setWhen(System.currentTimeMillis()) // the time stamp
 | 
			
		||||
						.setContentTitle(getText(R.string.app_name)) // the label of the entry
 | 
			
		||||
						.setContentText(text) // the contents of the entry
 | 
			
		||||
						.setContentIntent(contentIntent) // The intent to send when the entry is clicked
 | 
			
		||||
						.build();
 | 
			
		||||
 | 
			
		||||
			// Send the notification.
 | 
			
		||||
			//mNM.notify(NOTIFICATION, notification);
 | 
			
		||||
			startForeground(NOTIFICATION, notification);
 | 
			
		||||
			shown = true;
 | 
			
		||||
				// Send the notification.
 | 
			
		||||
				//mNM.notify(NOTIFICATION, notification);
 | 
			
		||||
				startForeground(NOTIFICATION, notification);
 | 
			
		||||
				shown = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ import java.util.TimerTask;
 | 
			
		|||
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.annotation.TargetApi;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.content.ActivityNotFoundException;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,9 +17,6 @@ import android.content.ServiceConnection;
 | 
			
		|||
import android.content.SharedPreferences;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.net.ConnectivityManager;
 | 
			
		||||
import android.net.Network;
 | 
			
		||||
import android.net.NetworkCapabilities;
 | 
			
		||||
import android.net.NetworkRequest;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +32,6 @@ import android.widget.Toast;
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.RequiresApi;
 | 
			
		||||
import androidx.core.app.ActivityCompat;
 | 
			
		||||
import androidx.core.content.ContextCompat;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -62,26 +57,31 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
 | 
			
		||||
	private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() {
 | 
			
		||||
		@Override
 | 
			
		||||
		public void daemonStateUpdate() {
 | 
			
		||||
			runOnUiThread(() -> {
 | 
			
		||||
				try {
 | 
			
		||||
					if (textView == null)
 | 
			
		||||
						return;
 | 
			
		||||
					Throwable tr = daemon.getLastThrowable();
 | 
			
		||||
					if (tr!=null) {
 | 
			
		||||
						textView.setText(throwableToString(tr));
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
					DaemonWrapper.State state = daemon.getState();
 | 
			
		||||
					String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : "";
 | 
			
		||||
					String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : "";
 | 
			
		||||
					textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr));
 | 
			
		||||
				} catch (Throwable tr) {
 | 
			
		||||
					Log.e(TAG,"error ignored",tr);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) {
 | 
			
		||||
			updateStatusText();
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	private void updateStatusText() {
 | 
			
		||||
		runOnUiThread(() -> {
 | 
			
		||||
			try {
 | 
			
		||||
				if (textView == null)
 | 
			
		||||
					return;
 | 
			
		||||
				Throwable tr = daemon.getLastThrowable();
 | 
			
		||||
				if (tr!=null) {
 | 
			
		||||
					textView.setText(throwableToString(tr));
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				DaemonWrapper.State state = daemon.getState();
 | 
			
		||||
				String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : "";
 | 
			
		||||
				String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : "";
 | 
			
		||||
				textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr));
 | 
			
		||||
			} catch (Throwable tr) {
 | 
			
		||||
				Log.e(TAG,"error ignored",tr);
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static volatile long graceStartedMillis;
 | 
			
		||||
	private static final Object graceStartedMillis_LOCK = new Object();
 | 
			
		||||
	private Menu optionsMenu;
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
		textView = new TextView(this);
 | 
			
		||||
		setContentView(textView);
 | 
			
		||||
		daemon.addStateChangeListener(daemonStateUpdatedListener);
 | 
			
		||||
		daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
		daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState());
 | 
			
		||||
 | 
			
		||||
		 // request permissions
 | 
			
		||||
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
			
		||||
| 
						 | 
				
			
			@ -372,9 +372,10 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
		if (gracefulQuitTimerOld != null)
 | 
			
		||||
			gracefulQuitTimerOld.cancel();
 | 
			
		||||
 | 
			
		||||
		if(daemon.GetTransitTunnelsCount() <= 0) { // no tunnels left
 | 
			
		||||
		if(daemon.getTransitTunnelsCount() <= 0) { // no tunnels left
 | 
			
		||||
			Log.d(TAG, "no transit tunnels left, stopping");
 | 
			
		||||
			i2pdStop();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		final Timer gracefulQuitTimer = new Timer(true);
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +391,7 @@ public class I2PDActivity extends Activity {
 | 
			
		|||
		final TimerTask tickerTask = new TimerTask() {
 | 
			
		||||
			@Override
 | 
			
		||||
			public void run() {
 | 
			
		||||
				daemonStateUpdatedListener.daemonStateUpdate();
 | 
			
		||||
				updateStatusText();
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue