From: Tobias Brunner Date: Fri, 20 Sep 2013 13:07:41 +0000 (+0200) Subject: android: Change state handling to display errors occurring while the app is hidden X-Git-Tag: 5.1.1dr4~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3817231333539a239d564ea74545c8881bc370c7;p=thirdparty%2Fstrongswan.git android: Change state handling to display errors occurring while the app is hidden A new connection ID allows listeners to track which errors they have already shown to the user or were already dismissed by the user. This was necessary because the state fragment is now unregistered from state changes when it is not shown. --- diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java index 305ee80b2d..853de561ed 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java @@ -190,7 +190,6 @@ public class CharonVpnService extends VpnService implements Runnable stopCurrentConnection(); if (mNextProfile == null) { - setProfile(null); setState(State.DISABLED); if (mTerminate) { @@ -207,10 +206,7 @@ public class CharonVpnService extends VpnService implements Runnable mCurrentCertificateAlias = mCurrentProfile.getCertificateAlias(); mCurrentUserCertificateAlias = mCurrentProfile.getUserCertificateAlias(); - setProfile(mCurrentProfile); - setError(ErrorState.NO_ERROR); - setState(State.CONNECTING); - setImcState(ImcState.UNKNOWN); + startConnection(mCurrentProfile); mIsDisconnecting = false; BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName()); @@ -258,17 +254,18 @@ public class CharonVpnService extends VpnService implements Runnable } /** - * Update the VPN profile on the state service. Called by the handler thread. + * Notify the state service about a new connection attempt. + * Called by the handler thread. * * @param profile currently active VPN profile */ - private void setProfile(VpnProfile profile) + private void startConnection(VpnProfile profile) { synchronized (mServiceLock) { if (mService != null) { - mService.setProfile(profile); + mService.startConnection(profile); } } } @@ -337,9 +334,9 @@ public class CharonVpnService extends VpnService implements Runnable { if (mService != null) { - mService.setError(error); if (!mIsDisconnecting) { + mService.setError(error); mService.disconnect(); } } diff --git a/src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java b/src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java index 2c530bad47..3b75a8f0bb 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java @@ -36,6 +36,7 @@ public class VpnStateService extends Service { private final List mListeners = new ArrayList(); private final IBinder mBinder = new LocalBinder(); + private long mConnectionID = 0; private Handler mHandler; private VpnProfile mProfile; private State mState = State.DISABLED; @@ -132,6 +133,19 @@ public class VpnStateService extends Service return mProfile; } + /** + * Get the current connection ID. May be used to track which state + * changes have already been handled. + * + * Is increased when startConnection() is called. + * + * @return connection ID + */ + public long getConnectionID() + { /* only updated from the main thread so no synchronization needed */ + return mConnectionID; + } + /** * Get the current state. * @@ -223,21 +237,26 @@ public class VpnStateService extends Service } /** - * Set the VPN profile currently active. Listeners are not notified. + * Called when a connection is started. Sets the currently active VPN + * profile, resets IMC and Error state variables, sets the State to + * CONNECTING, increases the connection ID, and notifies all listeners. * * May be called from threads other than the main thread. * * @param profile current profile */ - public void setProfile(final VpnProfile profile) + public void startConnection(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() { + notifyListeners(new Callable() { @Override - public void run() + public Boolean call() throws Exception { + VpnStateService.this.mConnectionID++; VpnStateService.this.mProfile = profile; + VpnStateService.this.mState = State.CONNECTING; + VpnStateService.this.mError = ErrorState.NO_ERROR; + VpnStateService.this.mImcState = ImcState.UNKNOWN; + return true; } }); } diff --git a/src/frontends/android/src/org/strongswan/android/ui/VpnStateFragment.java b/src/frontends/android/src/org/strongswan/android/ui/VpnStateFragment.java index 88f8df377f..d1394f65a8 100644 --- a/src/frontends/android/src/org/strongswan/android/ui/VpnStateFragment.java +++ b/src/frontends/android/src/org/strongswan/android/ui/VpnStateFragment.java @@ -49,9 +49,8 @@ import android.widget.TextView; public class VpnStateFragment extends Fragment implements VpnStateListener { - private static final String KEY_ERROR = "error"; - private static final String KEY_IMC_STATE = "imc_state"; - private static final String KEY_NAME = "name"; + private static final String KEY_ERROR_CONNECTION_ID = "error_connection_id"; + private static final String KEY_DISMISSED_CONNECTION_ID = "dismissed_connection_id"; private TextView mProfileNameView; private TextView mProfileView; @@ -59,11 +58,9 @@ public class VpnStateFragment extends Fragment implements VpnStateListener private int stateBaseColor; private Button mActionButton; private ProgressDialog mProgressDialog; - private State mState; private AlertDialog mErrorDialog; - private ErrorState mError; - private ImcState mImcState; - private String mErrorProfileName; + private long mErrorConnectionID; + private long mDismissedConnectionID; private VpnStateService mService; private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override @@ -91,13 +88,12 @@ public class VpnStateFragment extends Fragment implements VpnStateListener context.bindService(new Intent(context, VpnStateService.class), mServiceConnection, Service.BIND_AUTO_CREATE); - mError = ErrorState.NO_ERROR; - mImcState = ImcState.UNKNOWN; - if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR)) + mErrorConnectionID = 0; + mDismissedConnectionID = 0; + if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR_CONNECTION_ID)) { - mError = (ErrorState)savedInstanceState.getSerializable(KEY_ERROR); - mImcState = (ImcState)savedInstanceState.getSerializable(KEY_IMC_STATE); - mErrorProfileName = savedInstanceState.getString(KEY_NAME); + mErrorConnectionID = (Long)savedInstanceState.getSerializable(KEY_ERROR_CONNECTION_ID); + mDismissedConnectionID = (Long)savedInstanceState.getSerializable(KEY_DISMISSED_CONNECTION_ID); } } @@ -106,9 +102,8 @@ public class VpnStateFragment extends Fragment implements VpnStateListener { super.onSaveInstanceState(outState); - outState.putSerializable(KEY_ERROR, mError); - outState.putSerializable(KEY_IMC_STATE, mImcState); - outState.putString(KEY_NAME, mErrorProfileName); + outState.putSerializable(KEY_ERROR_CONNECTION_ID, mErrorConnectionID); + outState.putSerializable(KEY_DISMISSED_CONNECTION_ID, mDismissedConnectionID); } @Override @@ -179,37 +174,27 @@ public class VpnStateFragment extends Fragment implements VpnStateListener public void updateView() { + long connectionID = mService.getConnectionID(); + VpnProfile profile = mService.getProfile(); State state = mService.getState(); - ErrorState error = ErrorState.NO_ERROR; - ImcState imcState = ImcState.UNKNOWN; + ErrorState error = mService.getErrorState(); + ImcState imcState = mService.getImcState(); String name = "", gateway = ""; - if (state != State.DISABLED) + if (profile != null) { - VpnProfile profile = mService.getProfile(); - if (profile != null) - { - name = profile.getName(); - gateway = profile.getGateway(); - } - error = mService.getErrorState(); - imcState = mService.getImcState(); + name = profile.getName(); + gateway = profile.getGateway(); } - if (reportError(name, state, error, imcState)) + if (reportError(connectionID, name, error, imcState)) { return; } - if (state == mState) - { /* avoid unnecessary updates */ - return; - } - hideProgressDialog(); enableActionButton(false); mProfileNameView.setText(name); - mState = state; switch (state) { @@ -239,19 +224,11 @@ public class VpnStateFragment extends Fragment implements VpnStateListener } } - private boolean reportError(String name, State state, ErrorState error, ImcState imcState) + private boolean reportError(long connectionID, String name, ErrorState error, ImcState imcState) { - if (mError != ErrorState.NO_ERROR) - { /* we are currently reporting an error which was not yet dismissed */ - error = mError; - imcState = mImcState; - name = mErrorProfileName; - } - else if (error != ErrorState.NO_ERROR && (state == State.CONNECTING || state == State.CONNECTED)) - { /* while initiating we report errors */ - mError = error; - mImcState = imcState; - mErrorProfileName = name; + if (connectionID > mDismissedConnectionID) + { /* report error if it hasn't been dismissed yet */ + mErrorConnectionID = connectionID; } else { /* ignore all other errors */ @@ -332,8 +309,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener private void clearError() { - mError = ErrorState.NO_ERROR; - mImcState = ImcState.UNKNOWN; + mDismissedConnectionID = mErrorConnectionID; updateView(); } @@ -371,7 +347,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener private void showErrorDialog(int textid) { final List instructions = mService.getRemediationInstructions(); - final boolean show_instructions = mImcState == ImcState.BLOCK && !instructions.isEmpty(); + final boolean show_instructions = mService.getImcState() == ImcState.BLOCK && !instructions.isEmpty(); int text = show_instructions ? R.string.show_remediation_instructions : R.string.show_log; mErrorDialog = new AlertDialog.Builder(getActivity())