propagate from branch 'i2p.android.base' (head 473e458dab49137f8211dcad60554cd90078807d)

to branch 'i2p.android.base.zzz.graceful' (head 57a30f761ea3d230301347dbb8b79bd3540f97a2)
This commit is contained in:
str4d
2015-02-27 10:49:50 +00:00
5 changed files with 156 additions and 14 deletions

View File

@ -315,4 +315,32 @@ public class MainActivity extends I2PActivityBase implements
}
return false;
}
/** @since 0.9.18 */
public boolean isGracefulShutdownInProgress() {
RouterService svc = _routerService;
return svc != null && svc.isGracefulShutdownInProgress();
}
/** @since 0.9.18 */
public boolean onGracefulShutdownClicked() {
RouterService svc = _routerService;
if(svc != null && _isBound) {
setPref(PREF_AUTO_START, false);
svc.gracefulShutdown();
return true;
}
return false;
}
/** @since 0.9.18 */
public boolean onCancelGracefulShutdownClicked() {
RouterService svc = _routerService;
if(svc != null && _isBound) {
setPref(PREF_AUTO_START, false);
svc.cancelGracefulShutdown();
return true;
}
return false;
}
}

View File

@ -61,6 +61,12 @@ public class MainFragment extends I2PFragmentBase {
public boolean shouldBeOn();
public void onStartRouterClicked();
public boolean onStopRouterClicked();
/** @since 0.9.18 */
public boolean isGracefulShutdownInProgress();
/** @since 0.9.18 */
public boolean onGracefulShutdownClicked();
/** @since 0.9.18 */
public boolean onCancelGracefulShutdownClicked();
}
@Override
@ -118,8 +124,14 @@ public class MainFragment extends I2PFragmentBase {
updateOneShot();
checkFirstStart();
} else {
if(mCallback.onStopRouterClicked()) {
updateOneShot();
if (mCallback.isGracefulShutdownInProgress()) {
if(mCallback.onStopRouterClicked()) {
updateOneShot();
}
} else {
if(mCallback.onGracefulShutdownClicked()) {
updateOneShot();
}
}
}
return true;
@ -197,6 +209,21 @@ public class MainFragment extends I2PFragmentBase {
boolean isOn = mCallback.shouldBeOn();
b.setChecked(isOn);
if (isOn && mCallback.isGracefulShutdownInProgress()) {
RouterContext ctx = getRouterContext();
if (ctx != null) {
// TODO
// Don't change text on this button... hide it,
// and add two more buttons, one for cancel and one for shutdown immediately.
long ms = ctx.router().getShutdownTimeRemaining();
if (ms > 1000) {
b.setTextOn(getActivity().getResources().getString(R.string.button_router_graceful,
DataHelper.formatDuration(ms)));
} else {
b.setTextOn("Stopping I2P");
}
}
}
if (showOnOff && !isOn) {
// Sometimes the final state message from the RouterService
@ -249,6 +276,7 @@ public class MainFragment extends I2PFragmentBase {
newState == State.NETWORK_STOPPED) {
lightImage.setImageResource(R.drawable.routerlogo_0);
} else if (newState == State.STARTING ||
newState == State.GRACEFUL_SHUTDOWN ||
newState == State.STOPPING ||
newState == State.MANUAL_STOPPING ||
newState == State.MANUAL_QUITTING ||

View File

@ -87,7 +87,7 @@ public class RouterService extends Service {
Intent intent = new Intent(this, RouterService.class);
intent.putExtra(EXTRA_RESTART, true);
onStartCommand(intent, 12345, 67890);
} else if(lastState == State.MANUAL_QUITTING) {
} else if(lastState == State.MANUAL_QUITTING || lastState == State.GRACEFUL_SHUTDOWN) {
synchronized(_stateLock) {
setState(State.MANUAL_QUITTED);
stopSelf(); // Die.
@ -343,7 +343,7 @@ public class RouterService extends Service {
public void run() {
RouterContext ctx = _context;
if(ctx != null && (_state == State.RUNNING || _state == State.ACTIVE)) {
if(ctx != null && (_state == State.RUNNING || _state == State.ACTIVE || _state == State.GRACEFUL_SHUTDOWN)) {
Router router = ctx.router();
if(router.isAlive()) {
updateStatus(ctx);
@ -472,7 +472,8 @@ public class RouterService extends Service {
&& _state != State.STOPPING
&& _state != State.MANUAL_STOPPING
&& _state != State.MANUAL_QUITTING
&& _state != State.NETWORK_STOPPING) {
&& _state != State.NETWORK_STOPPING
&& _state != State.GRACEFUL_SHUTDOWN) {
return null;
}
return rv;
@ -486,11 +487,15 @@ public class RouterService extends Service {
}
public boolean canManualStop() {
return _state == State.WAITING || _state == State.STARTING || _state == State.RUNNING || _state == State.ACTIVE;
return _state == State.WAITING || _state == State.STARTING ||
_state == State.RUNNING || _state == State.ACTIVE ||
_state == State.GRACEFUL_SHUTDOWN;
}
/**
* Stop and don't restart the router, but keep the service
*
* Apparently unused - see manualQuit()
*/
public void manualStop() {
Util.d("manualStop called"
@ -502,7 +507,8 @@ public class RouterService extends Service {
if(_state == State.STARTING) {
_starterThread.interrupt();
}
if(_state == State.STARTING || _state == State.RUNNING || _state == State.ACTIVE) {
if(_state == State.STARTING || _state == State.RUNNING ||
_state == State.ACTIVE || _state == State.GRACEFUL_SHUTDOWN) {
_statusBar.replace(StatusBar.ICON_STOPPING, "Stopping I2P");
Thread stopperThread = new Thread(new Stopper(State.MANUAL_STOPPING, State.MANUAL_STOPPED));
stopperThread.start();
@ -523,7 +529,8 @@ public class RouterService extends Service {
if(_state == State.STARTING) {
_starterThread.interrupt();
}
if(_state == State.STARTING || _state == State.RUNNING || _state == State.ACTIVE) {
if(_state == State.STARTING || _state == State.RUNNING ||
_state == State.ACTIVE || _state == State.GRACEFUL_SHUTDOWN) {
_statusBar.replace(StatusBar.ICON_STOPPING, "Stopping I2P");
Thread stopperThread = new Thread(new Stopper(State.MANUAL_QUITTING, State.MANUAL_QUITTED));
stopperThread.start();
@ -544,7 +551,8 @@ public class RouterService extends Service {
if(_state == State.STARTING) {
_starterThread.interrupt();
}
if(_state == State.STARTING || _state == State.RUNNING || _state == State.ACTIVE) {
if(_state == State.STARTING || _state == State.RUNNING ||
_state == State.ACTIVE || _state == State.GRACEFUL_SHUTDOWN) {
_statusBar.replace(StatusBar.ICON_STOPPING, "Network disconnected, stopping I2P");
// don't change state, let the shutdown hook do it
Thread stopperThread = new Thread(new Stopper(State.NETWORK_STOPPING, State.NETWORK_STOPPING));
@ -572,6 +580,79 @@ public class RouterService extends Service {
}
}
/**
* Graceful Shutdown
*
* @since 0.9.18
*/
public boolean isGracefulShutdownInProgress() {
if (_state == State.GRACEFUL_SHUTDOWN) {
RouterContext ctx = _context;
return ctx != null && ctx.router().gracefulShutdownInProgress();
}
return false;
}
/**
* Graceful Shutdown
*
* @since 0.9.18
*/
public void gracefulShutdown() {
Util.d("gracefulShutdown called"
+ " Current state is: " + _state);
synchronized(_stateLock) {
if(!canManualStop()) {
return;
}
if(_state == State.STARTING || _state == State.WAITING) {
manualQuit();
return;
}
if(_state == State.RUNNING || _state == State.ACTIVE) {
RouterContext ctx = _context;
if(ctx != null && ctx.router().isAlive()) {
int part = ctx.tunnelManager().getParticipatingCount();
if(part <= 0) {
manualQuit();
} else {
ctx.router().shutdownGracefully();
long ms = ctx.router().getShutdownTimeRemaining();
if (ms > 1000) {
_statusBar.replace(StatusBar.ICON_STOPPING, "Stopping I2P in " + DataHelper.formatDuration(ms));
} else {
_statusBar.replace(StatusBar.ICON_STOPPING, "Stopping I2P");
}
setState(State.GRACEFUL_SHUTDOWN);
}
}
}
}
}
/**
* Cancel Graceful Shutdown
*
* @since 0.9.18
*/
public void cancelGracefulShutdown() {
Util.d("cancelGracefulShutdown called"
+ " Current state is: " + _state);
synchronized(_stateLock) {
if(_state != State.GRACEFUL_SHUTDOWN) {
return;
}
RouterContext ctx = _context;
if(ctx != null && ctx.router().isAlive()) {
ctx.router().cancelGracefulShutdown();
_statusBar.replace(StatusBar.ICON_RUNNING, "Shutdown cancelled");
setState(State.RUNNING);
}
}
}
// ******** end methods accessed from Activities and Receivers ************
private static final int STATE_MSG = 1;
@ -631,7 +712,8 @@ public class RouterService extends Service {
if(_state == State.STARTING) {
_starterThread.interrupt();
}
if(_state == State.STARTING || _state == State.RUNNING || _state == State.ACTIVE) {
if(_state == State.STARTING || _state == State.RUNNING ||
_state == State.ACTIVE || _state == State.GRACEFUL_SHUTDOWN) {
// should this be in a thread?
_statusBar.replace(StatusBar.ICON_SHUTTING_DOWN, "I2P is shutting down");
Thread stopperThread = new Thread(new Stopper(State.STOPPING, State.STOPPED));
@ -708,7 +790,8 @@ public class RouterService extends Service {
_starterThread.interrupt();
}
if(_state == State.WAITING || _state == State.STARTING
|| _state == State.RUNNING || _state == State.ACTIVE) {
|| _state == State.RUNNING || _state == State.ACTIVE
|| _state == State.GRACEFUL_SHUTDOWN) {
setState(State.STOPPING);
}
}
@ -750,7 +833,7 @@ public class RouterService extends Service {
mStateCallbacks.kill();
stopForeground(true);
stopSelf();
} else if(_state == State.MANUAL_QUITTING) {
} else if(_state == State.MANUAL_QUITTING || _state == State.GRACEFUL_SHUTDOWN) {
setState(State.MANUAL_QUITTED);
// Unregister all callbacks.
mStateCallbacks.kill();

View File

@ -27,6 +27,7 @@
<string name="button_router_off">Long press to start I2P</string>
<string name="button_router_on">I2P is running (long press to stop)</string>
<string name="button_router_graceful">I2P is shutting down in %s (long press to stop immediately)</string>
<!-- Character to indicate a client tunnel. Usually first letter of the word "client". -->
<string name="char_client_tunnel">C</string>
@ -227,4 +228,4 @@
<string name="logs_copied_to_clipboard">Logs copied to clipboard</string>
<string name="label_browser_configuration">Browser configuration</string>
</resources>
</resources>

View File

@ -19,7 +19,9 @@ public enum State implements Parcelable {
// 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;
NETWORK_STOPPING, NETWORK_STOPPED,
/** @since 0.9.18 */
GRACEFUL_SHUTDOWN;
@Override
public int describeContents() {