]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java
android: Add a parser for XML remediation instructions
[thirdparty/strongswan.git] / src / frontends / android / src / org / strongswan / android / logic / VpnStateService.java
CommitLineData
d1220566 1/*
dc52cfab 2 * Copyright (C) 2012-2013 Tobias Brunner
d1220566
TB
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16package org.strongswan.android.logic;
17
18import java.util.ArrayList;
19import java.util.List;
20import java.util.concurrent.Callable;
21
22import org.strongswan.android.data.VpnProfile;
dc52cfab 23import org.strongswan.android.logic.imc.ImcState;
d1220566
TB
24
25import android.app.Service;
1b887772 26import android.content.Context;
d1220566
TB
27import android.content.Intent;
28import android.os.Binder;
29import android.os.Handler;
30import android.os.IBinder;
31
32public class VpnStateService extends Service
33{
34 private final List<VpnStateListener> mListeners = new ArrayList<VpnStateListener>();
35 private final IBinder mBinder = new LocalBinder();
36 private Handler mHandler;
37 private VpnProfile mProfile;
38 private State mState = State.DISABLED;
39 private ErrorState mError = ErrorState.NO_ERROR;
dc52cfab 40 private ImcState mImcState = ImcState.UNKNOWN;
d1220566
TB
41
42 public enum State
43 {
44 DISABLED,
45 CONNECTING,
46 CONNECTED,
47 DISCONNECTING,
48 }
49
50 public enum ErrorState
51 {
52 NO_ERROR,
53 AUTH_FAILED,
54 PEER_AUTH_FAILED,
55 LOOKUP_FAILED,
56 UNREACHABLE,
57 GENERIC_ERROR,
58 }
59
60 /**
61 * Listener interface for bound clients that are interested in changes to
62 * this Service.
63 */
64 public interface VpnStateListener
65 {
66 public void stateChanged();
67 }
68
69 /**
70 * Simple Binder that allows to directly access this Service class itself
71 * after binding to it.
72 */
73 public class LocalBinder extends Binder
74 {
75 public VpnStateService getService()
76 {
77 return VpnStateService.this;
78 }
79 }
80
81 @Override
82 public void onCreate()
83 {
84 /* this handler allows us to notify listeners from the UI thread and
85 * not from the threads that actually report any state changes */
86 mHandler = new Handler();
87 }
88
89 @Override
90 public IBinder onBind(Intent intent)
91 {
92 return mBinder;
93 }
94
95 @Override
96 public void onDestroy()
97 {
98 }
99
100 /**
101 * Register a listener with this Service. We assume this is called from
102 * the main thread so no synchronization is happening.
103 *
104 * @param listener listener to register
105 */
106 public void registerListener(VpnStateListener listener)
107 {
108 mListeners.add(listener);
109 }
110
111 /**
112 * Unregister a listener from this Service.
113 *
114 * @param listener listener to unregister
115 */
116 public void unregisterListener(VpnStateListener listener)
117 {
118 mListeners.remove(listener);
119 }
120
121 /**
122 * Get the current VPN profile.
123 *
124 * @return profile
125 */
126 public VpnProfile getProfile()
127 { /* only updated from the main thread so no synchronization needed */
128 return mProfile;
129 }
130
131 /**
132 * Get the current state.
133 *
134 * @return state
135 */
136 public State getState()
137 { /* only updated from the main thread so no synchronization needed */
138 return mState;
139 }
140
141 /**
142 * Get the current error, if any.
143 *
144 * @return error
145 */
146 public ErrorState getErrorState()
147 { /* only updated from the main thread so no synchronization needed */
148 return mError;
149 }
150
dc52cfab
TB
151 /**
152 * Get the current IMC state, if any.
153 *
154 * @return imc state
155 */
156 public ImcState getImcState()
157 { /* only updated from the main thread so no synchronization needed */
158 return mImcState;
159 }
160
1b887772
TB
161 /**
162 * Disconnect any existing connection and shutdown the daemon, the
163 * VpnService is not stopped but it is reset so new connections can be
164 * started.
165 */
166 public void disconnect()
167 {
168 /* as soon as the TUN device is created by calling establish() on the
169 * VpnService.Builder object the system binds to the service and keeps
170 * bound until the file descriptor of the TUN device is closed. thus
171 * calling stopService() here would not stop (destroy) the service yet,
172 * instead we call startService() with an empty Intent which shuts down
173 * the daemon (and closes the TUN device, if any) */
174 Context context = getApplicationContext();
175 Intent intent = new Intent(context, CharonVpnService.class);
176 context.startService(intent);
177 }
178
d1220566
TB
179 /**
180 * Update state and notify all listeners about the change. By using a Handler
181 * this is done from the main UI thread and not the initial reporter thread.
182 * Also, in doing the actual state change from the main thread, listeners
183 * see all changes and none are skipped.
184 *
185 * @param change the state update to perform before notifying listeners, returns true if state changed
186 */
187 private void notifyListeners(final Callable<Boolean> change)
188 {
189 mHandler.post(new Runnable() {
190 @Override
191 public void run()
192 {
193 try
194 {
195 if (change.call())
196 { /* otherwise there is no need to notify the listeners */
197 for (VpnStateListener listener : mListeners)
198 {
199 listener.stateChanged();
200 }
201 }
202 }
203 catch (Exception e)
204 {
205 e.printStackTrace();
206 }
207 }
208 });
209 }
210
211 /**
212 * Set the VPN profile currently active. Listeners are not notified.
213 *
214 * May be called from threads other than the main thread.
215 *
216 * @param profile current profile
217 */
218 public void setProfile(final VpnProfile profile)
219 {
220 /* even though we don't notify the listeners the update is done from the
221 * same handler so updates are predictable for listeners */
222 mHandler.post(new Runnable() {
223 @Override
224 public void run()
225 {
226 VpnStateService.this.mProfile = profile;
227 }
228 });
229 }
230
231 /**
232 * Update the state and notify all listeners, if changed.
233 *
234 * May be called from threads other than the main thread.
235 *
236 * @param state new state
237 */
238 public void setState(final State state)
239 {
240 notifyListeners(new Callable<Boolean>() {
241 @Override
242 public Boolean call() throws Exception
243 {
244 if (VpnStateService.this.mState != state)
245 {
246 VpnStateService.this.mState = state;
247 return true;
248 }
249 return false;
250 }
251 });
252 }
253
254 /**
255 * Set the current error state and notify all listeners, if changed.
256 *
257 * May be called from threads other than the main thread.
258 *
259 * @param error error state
260 */
261 public void setError(final ErrorState error)
262 {
263 notifyListeners(new Callable<Boolean>() {
264 @Override
265 public Boolean call() throws Exception
266 {
267 if (VpnStateService.this.mError != error)
268 {
269 VpnStateService.this.mError = error;
270 return true;
271 }
272 return false;
273 }
274 });
275 }
dc52cfab
TB
276
277 /**
278 * Set the current IMC state and notify all listeners, if changed.
279 *
280 * May be called from threads other than the main thread.
281 *
282 * @param error error state
283 */
284 public void setImcState(final ImcState state)
285 {
286 notifyListeners(new Callable<Boolean>() {
287 @Override
288 public Boolean call() throws Exception
289 {
290 if (VpnStateService.this.mImcState != state)
291 {
292 VpnStateService.this.mImcState = state;
293 return true;
294 }
295 return false;
296 }
297 });
298 }
d1220566 299}