I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 07e6e293 authored by str4d's avatar str4d
Browse files

AIDL interface for getting router status, used for MainFragment status images

Other apps can use this interface by copying the AIDL files into their source
tree.
parent 2dd1655e
No related branches found
No related tags found
No related merge requests found
......@@ -369,7 +369,7 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
* Bind only
*/
protected boolean bindRouter(boolean autoCreate) {
Intent intent = new Intent();
Intent intent = new Intent(RouterBinder.class.getName());
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
Util.i(this + " calling bindService");
_connection = new RouterConnection();
......@@ -389,6 +389,9 @@ public abstract class I2PActivityBase extends ActionBarActivity implements
_isBound = false;
}
/**
* Class for interacting with the main interface of the RouterService.
*/
protected class RouterConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
......
......@@ -2,28 +2,39 @@ package net.i2p.android.router;
import java.io.File;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import net.i2p.android.router.R;
import net.i2p.android.router.service.IRouterState;
import net.i2p.android.router.service.IRouterStateCallback;
import net.i2p.android.router.service.RouterService;
import net.i2p.android.router.util.Util;
public class MainActivity extends I2PActivityBase implements
MainFragment.RouterControlListener,
VersionDialog.VersionDialogListener {
IRouterState mStateService = null;
MainFragment mMainFragment = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Start with the home view
if (savedInstanceState == null) {
MainFragment mainFragment = new MainFragment();
mainFragment.setArguments(getIntent().getExtras());
mMainFragment = new MainFragment();
mMainFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(R.id.main_fragment, mainFragment).commit();
.add(R.id.main_fragment, mMainFragment).commit();
}
}
......@@ -62,15 +73,112 @@ public class MainActivity extends I2PActivityBase implements
}
}
@Override
public void onStop() {
if (mStateService != null) {
try {
mStateService.unregisterCallback(mStateCallback);
} catch (RemoteException e) {}
unbindService(mStateConnection);
}
super.onStop();
}
@Override
protected void onRouterBind(RouterService svc) {
if (mStateService == null) {
// Try binding for state updates.
// Don't auto-create the RouterService.
Intent intent = new Intent(IRouterState.class.getName());
intent.setClassName(this, "net.i2p.android.router.service.RouterService");
boolean b = bindService(intent,
mStateConnection, 0);
Util.i("Bind to IRouterState successful: " + b);
}
super.onRouterBind(svc);
}
private ServiceConnection mStateConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mStateService = IRouterState.Stub.asInterface(service);
try {
if (mStateService.isStarted()) {
mStateService.registerCallback(mStateCallback);
// Update for the current state.
String curState = mStateService.getState();
Message msg = mHandler.obtainMessage(STATE_MSG);
msg.getData().putString("state", curState);
mHandler.sendMessage(msg);
} else {
// Unbind
unbindService(mStateConnection);
}
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mStateService = null;
}
};
private IRouterStateCallback mStateCallback = new IRouterStateCallback.Stub() {
/**
* This is called by the RouterService regularly to tell us about
* new states. Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void stateChanged(String newState) throws RemoteException {
Message msg = mHandler.obtainMessage(STATE_MSG);
msg.getData().putString("state", newState);
mHandler.sendMessage(msg);
}
};
private static final int STATE_MSG = 1;
private Handler mHandler = new Handler() {
private String lastRouterState = null;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STATE_MSG:
String state = msg.getData().getString("state");
if (lastRouterState == null || !lastRouterState.equals(state)) {
if (mMainFragment == null)
mMainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.main_fragment);
if (mMainFragment != null) {
mMainFragment.updateState(state);
lastRouterState = state;
}
}
break;
default:
super.handleMessage(msg);
}
}
};
// MainFragment.RouterControlListener
public boolean shouldShowStart() {
public boolean shouldShowOnOff() {
RouterService svc = _routerService;
return ((svc == null) || (!_isBound) || svc.canManualStart())
&& Util.isConnected(this);
return (((svc == null) || (!_isBound) || svc.canManualStart())
&& Util.isConnected(this))
|| (svc != null && _isBound && svc.canManualStop());
}
public boolean shouldShowStop() {
public boolean shouldBeOn() {
RouterService svc = _routerService;
return svc != null && _isBound && svc.canManualStop();
}
......
......@@ -32,8 +32,8 @@ public class MainFragment extends I2PFragmentBase {
// Container Activity must implement this interface
public interface RouterControlListener {
public boolean shouldShowStart();
public boolean shouldShowStop();
public boolean shouldShowOnOff();
public boolean shouldBeOn();
public void onStartRouterClicked();
public boolean onStopRouterClicked();
}
......@@ -90,14 +90,10 @@ public class MainFragment extends I2PFragmentBase {
boolean on = ((ToggleButton) view).isChecked();
if (on) {
_startPressed = true;
lightImage.setImageResource(R.drawable.routerled_ry);
((AnimationDrawable) lightImage.getDrawable()).start();
mCallback.onStartRouterClicked();
updateOneShot();
} else {
if(mCallback.onStopRouterClicked()) {
lightImage.setImageResource(R.drawable.routerled_ry);
((AnimationDrawable) lightImage.getDrawable()).start();
updateOneShot();
}
}
......@@ -148,6 +144,7 @@ public class MainFragment extends I2PFragmentBase {
private class OneShotUpdate implements Runnable {
public void run() {
updateVisibility();
updateStatus();
}
}
......@@ -158,6 +155,7 @@ public class MainFragment extends I2PFragmentBase {
private final int delay = 1000;
private final int toloop = delay / 500;
public void run() {
updateVisibility();
if(counter++ % toloop == 0) {
updateStatus();
}
......@@ -166,6 +164,15 @@ public class MainFragment extends I2PFragmentBase {
}
}
private void updateVisibility() {
boolean showOnOff = mCallback.shouldShowOnOff();
ToggleButton b = (ToggleButton) getActivity().findViewById(R.id.router_onoff_button);
b.setVisibility(showOnOff ? View.VISIBLE : View.INVISIBLE);
boolean isOn = mCallback.shouldBeOn();
b.setChecked(isOn);
}
public boolean onBackPressed() {
RouterContext ctx = getRouterContext();
// RouterService svc = _routerService; Which is better to use?!
......@@ -199,6 +206,28 @@ public class MainFragment extends I2PFragmentBase {
}
}
public void updateState(String newState) {
final ImageView lightImage = (ImageView) getView().findViewById(R.id.main_lights);
if ("INIT".equals(newState) ||
"STOPPED".equals(newState) ||
"MANUAL_STOPPED".equals(newState) ||
"MANUAL_QUITTED".equals(newState) ||
"NETWORK_STOPPED".equals(newState)) {
lightImage.setImageResource(R.drawable.routerled_r);
} else if ("STARTING".equals(newState) ||
"STOPPING".equals(newState) ||
"MANUAL_STOPPING".equals(newState) ||
"MANUAL_QUITTING".equals(newState) ||
"NETWORK_STOPPING".equals(newState)) {
lightImage.setImageResource(R.drawable.routerled_ry);
((AnimationDrawable) lightImage.getDrawable()).start();
} else if ("RUNNING".equals(newState)) {
lightImage.setImageResource(R.drawable.routerled_y);
} else if ("WAITING".equals(newState)) {
lightImage.setImageResource(R.drawable.routerled_r);
} // Ignore unknown states.
}
private void updateStatus() {
RouterContext ctx = getRouterContext();
TextView tv = (TextView) getActivity().findViewById(R.id.main_status_text);
......
package net.i2p.android.router.service;
import net.i2p.android.router.service.IRouterStateCallback;
/**
* An interface for determining the state of the I2P RouterService.
*/
interface IRouterState {
/**
* This allows I2P to inform on state changes.
*/
void registerCallback(IRouterStateCallback cb);
/**
* Remove registered callback interface.
*/
void unregisterCallback(IRouterStateCallback cb);
/**
* Determines whether the RouterService has been started. If it hasn't, no
* state changes will ever occur from this RouterService instance, and the
* client should unbind and inform the user that the I2P router is not
* running (and optionally send a ROUTER_START Intent to
* net.i2p.android.router.MainActivity).
*/
boolean isStarted();
/**
* Get the state of the I2P router
**/
String getState();
}
package net.i2p.android.router.service;
/**
* Callback interface used to send synchronous notifications of the current
* RouterService state back to registered clients. Note that this is a
* one-way interface so the server does not block waiting for the client.
*/
oneway interface IRouterStateCallback {
/**
* Called when the state of the I2P router changes
*/
void stateChanged(String newState);
}
......@@ -5,6 +5,10 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
......@@ -52,13 +56,23 @@ public class RouterService extends Service {
private final Object _stateLock = new Object();
private Handler _handler;
private Runnable _updater;
private boolean mStartCalled;
private static final String SHARED_PREFS = "net.i2p.android.router";
private static final String LAST_STATE = "service.lastState";
private static final String EXTRA_RESTART = "restart";
private static final String MARKER = "************************************** ";
/**
* This is a list of callbacks that have been registered with the
* service. Note that this is package scoped (instead of private) so
* that it can be accessed more efficiently from inner classes.
*/
final RemoteCallbackList<IRouterStateCallback> mStateCallbacks
= new RemoteCallbackList<IRouterStateCallback>();
@Override
public void onCreate() {
mStartCalled = false;
State lastState = getSavedState();
setState(State.INIT);
Util.i(this + " onCreate called"
......@@ -99,6 +113,7 @@ public class RouterService extends Service {
+ " Flags is: " + flags
+ " ID is: " + startId
+ " Current state is: " + _state);
mStartCalled = true;
boolean restart = intent != null && intent.getBooleanExtra(EXTRA_RESTART, false);
if(restart) {
Util.i(this + " RESTARTING");
......@@ -402,9 +417,46 @@ public class RouterService extends Service {
public IBinder onBind(Intent intent) {
Util.i(this + "onBind called"
+ " Current state is: " + _state);
return _binder;
Util.i("Intent action: " + intent.getAction());
// Select the interface to return.
if (RouterBinder.class.getName().equals(intent.getAction())) {
// Local Activity wanting access to the RouterContext
Util.i("Returning RouterContext binder");
return _binder;
}
if (IRouterState.class.getName().equals(intent.getAction())) {
// Someone wants to monitor the router state.
Util.i("Returning state binder");
return mStatusBinder;
}
Util.i("Unknown binder request, returning null");
return null;
}
/**
* IRouterState is defined through IDL
*/
private final IRouterState.Stub mStatusBinder = new IRouterState.Stub() {
public void registerCallback(IRouterStateCallback cb)
throws RemoteException {
if (cb != null) mStateCallbacks.register(cb);
}
public void unregisterCallback(IRouterStateCallback cb)
throws RemoteException {
if (cb != null) mStateCallbacks.unregister(cb);
}
public boolean isStarted() throws RemoteException {
return mStartCalled;
}
public String getState() throws RemoteException {
return _state.name();
}
};
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
......@@ -527,6 +579,36 @@ public class RouterService extends Service {
}
// ******** end methods accessed from Activities and Receivers ************
private static final int STATE_MSG = 1;
/**
* Our Handler used to execute operations on the main thread.
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STATE_MSG:
String state = _state.name();
// Broadcast to all clients the new state.
final int N = mStateCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mStateCallbacks.getBroadcastItem(i).stateChanged(state);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mStateCallbacks.finishBroadcast();
break;
default:
super.handleMessage(msg);
}
}
};
/**
* Turn off the status bar. Unregister the receiver. If we were running,
* fire up the Stopper thread.
......@@ -670,10 +752,14 @@ public class RouterService extends Service {
|| _state == State.STOPPING) {
Util.i(this + " died of unknown causes");
setState(State.STOPPED);
// Unregister all callbacks.
mStateCallbacks.kill();
stopForeground(true);
stopSelf();
} else if(_state == State.MANUAL_QUITTING) {
setState(State.MANUAL_QUITTED);
// Unregister all callbacks.
mStateCallbacks.kill();
stopForeground(true);
stopSelf();
}
......@@ -698,6 +784,7 @@ public class RouterService extends Service {
private void setState(State s) {
_state = s;
saveState();
mHandler.sendEmptyMessage(STATE_MSG);
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment