Service added that keeps track of VPN state and notifies listeners about changes
It is ensured that listeners are notified only from the main thread.
This commit is contained in:
@@ -25,6 +25,10 @@
|
|||||||
android:name=".ui.VpnProfileDetailActivity" >
|
android:name=".ui.VpnProfileDetailActivity" >
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".logic.VpnStateService"
|
||||||
|
android:exported="false" >
|
||||||
|
</service>
|
||||||
<service
|
<service
|
||||||
android:name=".logic.CharonVpnService"
|
android:name=".logic.CharonVpnService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Tobias Brunner
|
||||||
|
* Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.strongswan.android.logic;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import org.strongswan.android.data.VpnProfile;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
public class VpnStateService extends Service
|
||||||
|
{
|
||||||
|
private final List<VpnStateListener> mListeners = new ArrayList<VpnStateListener>();
|
||||||
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
private Handler mHandler;
|
||||||
|
private VpnProfile mProfile;
|
||||||
|
private State mState = State.DISABLED;
|
||||||
|
private ErrorState mError = ErrorState.NO_ERROR;
|
||||||
|
|
||||||
|
public enum State
|
||||||
|
{
|
||||||
|
DISABLED,
|
||||||
|
CONNECTING,
|
||||||
|
CONNECTED,
|
||||||
|
DISCONNECTING,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ErrorState
|
||||||
|
{
|
||||||
|
NO_ERROR,
|
||||||
|
AUTH_FAILED,
|
||||||
|
PEER_AUTH_FAILED,
|
||||||
|
LOOKUP_FAILED,
|
||||||
|
UNREACHABLE,
|
||||||
|
GENERIC_ERROR,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener interface for bound clients that are interested in changes to
|
||||||
|
* this Service.
|
||||||
|
*/
|
||||||
|
public interface VpnStateListener
|
||||||
|
{
|
||||||
|
public void stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Binder that allows to directly access this Service class itself
|
||||||
|
* after binding to it.
|
||||||
|
*/
|
||||||
|
public class LocalBinder extends Binder
|
||||||
|
{
|
||||||
|
public VpnStateService getService()
|
||||||
|
{
|
||||||
|
return VpnStateService.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate()
|
||||||
|
{
|
||||||
|
/* this handler allows us to notify listeners from the UI thread and
|
||||||
|
* not from the threads that actually report any state changes */
|
||||||
|
mHandler = new Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent)
|
||||||
|
{
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener with this Service. We assume this is called from
|
||||||
|
* the main thread so no synchronization is happening.
|
||||||
|
*
|
||||||
|
* @param listener listener to register
|
||||||
|
*/
|
||||||
|
public void registerListener(VpnStateListener listener)
|
||||||
|
{
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a listener from this Service.
|
||||||
|
*
|
||||||
|
* @param listener listener to unregister
|
||||||
|
*/
|
||||||
|
public void unregisterListener(VpnStateListener listener)
|
||||||
|
{
|
||||||
|
mListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current VPN profile.
|
||||||
|
*
|
||||||
|
* @return profile
|
||||||
|
*/
|
||||||
|
public VpnProfile getProfile()
|
||||||
|
{ /* only updated from the main thread so no synchronization needed */
|
||||||
|
return mProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current state.
|
||||||
|
*
|
||||||
|
* @return state
|
||||||
|
*/
|
||||||
|
public State getState()
|
||||||
|
{ /* only updated from the main thread so no synchronization needed */
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current error, if any.
|
||||||
|
*
|
||||||
|
* @return error
|
||||||
|
*/
|
||||||
|
public ErrorState getErrorState()
|
||||||
|
{ /* only updated from the main thread so no synchronization needed */
|
||||||
|
return mError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update state and notify all listeners about the change. By using a Handler
|
||||||
|
* this is done from the main UI thread and not the initial reporter thread.
|
||||||
|
* Also, in doing the actual state change from the main thread, listeners
|
||||||
|
* see all changes and none are skipped.
|
||||||
|
*
|
||||||
|
* @param change the state update to perform before notifying listeners, returns true if state changed
|
||||||
|
*/
|
||||||
|
private void notifyListeners(final Callable<Boolean> change)
|
||||||
|
{
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (change.call())
|
||||||
|
{ /* otherwise there is no need to notify the listeners */
|
||||||
|
for (VpnStateListener listener : mListeners)
|
||||||
|
{
|
||||||
|
listener.stateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the VPN profile currently active. Listeners are not notified.
|
||||||
|
*
|
||||||
|
* May be called from threads other than the main thread.
|
||||||
|
*
|
||||||
|
* @param profile current profile
|
||||||
|
*/
|
||||||
|
public void setProfile(final VpnProfile profile)
|
||||||
|
{
|
||||||
|
/* even though we don't notify the listeners the update is done from the
|
||||||
|
* same handler so updates are predictable for listeners */
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
VpnStateService.this.mProfile = profile;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the state and notify all listeners, if changed.
|
||||||
|
*
|
||||||
|
* May be called from threads other than the main thread.
|
||||||
|
*
|
||||||
|
* @param state new state
|
||||||
|
*/
|
||||||
|
public void setState(final State state)
|
||||||
|
{
|
||||||
|
notifyListeners(new Callable<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean call() throws Exception
|
||||||
|
{
|
||||||
|
if (VpnStateService.this.mState != state)
|
||||||
|
{
|
||||||
|
VpnStateService.this.mState = state;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current error state and notify all listeners, if changed.
|
||||||
|
*
|
||||||
|
* May be called from threads other than the main thread.
|
||||||
|
*
|
||||||
|
* @param error error state
|
||||||
|
*/
|
||||||
|
public void setError(final ErrorState error)
|
||||||
|
{
|
||||||
|
notifyListeners(new Callable<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean call() throws Exception
|
||||||
|
{
|
||||||
|
if (VpnStateService.this.mError != error)
|
||||||
|
{
|
||||||
|
VpnStateService.this.mError = error;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user